Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.utility/src')
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Command.java66
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutor.java52
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java53
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Filter.java73
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/JavaType.java105
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java63
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AbstractAssociation.java50
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Association.java46
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Bag.java187
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiFilter.java80
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiStringConverter.java127
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiTransformer.java81
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BitTools.java214
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BooleanHolder.java126
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java1678
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java911
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java3918
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Counter.java109
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/EmptyIterable.java50
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java1006
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/HashBag.java914
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IdentityHashBag.java879
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java148
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java349
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java167
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ListenerList.java117
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java358
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NullList.java150
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Range.java87
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java40
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleAssociation.java69
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleFilter.java107
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java231
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java234
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java95
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java259
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java73
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringConverter.java68
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java58
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java4108
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java374
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java372
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java279
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Transformer.java69
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/XMLStringEncoder.java182
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java72
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java78
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ChainIterator.java145
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java154
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java253
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeIterator.java126
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java194
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyEnumeration.java55
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java59
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java83
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EnumerationIterator.java50
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java134
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GenericIteratorWrapper.java47
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java242
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/IteratorEnumeration.java47
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/PeekableIterator.java100
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java178
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyIterator.java61
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyListIterator.java93
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ResultSetIterator.java154
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementIterator.java63
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementListIterator.java94
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationIterator.java80
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationListIterator.java108
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TreeIterator.java194
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java996
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/CallbackChangeSupport.java83
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/ChangeSupport.java2363
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/SingleAspectChangeSupport.java331
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTCollectionChangeListenerWrapper.java150
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTListChangeListenerWrapper.java198
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java75
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java74
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTTreeChangeListenerWrapper.java150
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java194
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java279
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java179
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java345
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationPropertyValueModel.java112
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationWritablePropertyValueModel.java107
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java238
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java296
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java140
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java179
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java406
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java574
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java204
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java171
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java138
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java125
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java295
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java97
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java103
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java84
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java74
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java97
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java287
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java300
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java220
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java166
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java206
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java58
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java71
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java50
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java52
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java255
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java194
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyListValueModelAdapter.java219
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java145
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java183
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java316
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java66
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java132
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java100
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java63
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java78
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java54
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java59
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java241
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java131
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java127
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java215
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java137
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java157
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java86
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java92
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java75
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java66
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java84
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java345
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java200
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java216
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java43
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java49
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java140
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java198
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java362
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java286
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java218
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java223
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java427
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java233
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java151
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java207
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java410
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java224
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java722
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java939
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AsynchronousValidator.java50
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/DefaultProblem.java79
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Node.java419
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java121
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Problem.java46
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/RunnableValidation.java128
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/SynchronousValidator.java44
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CachingComboBoxModel.java42
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java206
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java328
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/Displayable.java93
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/EmptyIcon.java54
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java140
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java455
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java425
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NodeSelector.java32
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NonCachingComboBoxModel.java73
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleDisplayable.java177
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListBrowser.java86
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListCellRenderer.java128
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java186
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/TableCellEditorAdapter.java96
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/Model.java195
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ChangeEvent.java64
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/CollectionChangeEvent.java137
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ListChangeEvent.java262
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/PropertyChangeEvent.java104
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/StateChangeEvent.java57
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/TreeChangeEvent.java111
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ChangeListener.java25
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeAdapter.java48
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeListener.java60
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeAdapter.java56
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeListener.java80
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/MultiMethodReflectiveChangeListener.java145
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/PropertyChangeListener.java35
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ReflectiveChangeListener.java312
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/SingleMethodReflectiveChangeListener.java60
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/StateChangeListener.java35
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeAdapter.java48
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeListener.java62
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/CollectionValueModel.java40
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/ListValueModel.java55
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/PropertyValueModel.java34
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeNodeValueModel.java71
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeValueModel.java34
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/WritablePropertyValueModel.java31
200 files changed, 0 insertions, 46350 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Command.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Command.java
deleted file mode 100644
index ffabf124af..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Command.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility;
-
-/**
- * Simple interface for implementing the GOF Command design pattern.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface Command {
-
- /**
- * Execute the command. The semantics of the command
- * is determined by the contract between the client and server.
- */
- void execute();
-
- final class Null implements Command {
- public static final Command INSTANCE = new Null();
- public static Command instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- public void execute() {
- // do nothing
- }
- @Override
- public String toString() {
- return "Command.Null";
- }
- }
-
- final class Disabled implements Command {
- public static final Command INSTANCE = new Disabled();
- public static Command instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public void execute() {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "Command.Disabled";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutor.java
deleted file mode 100644
index f58dbf6674..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutor.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility;
-
-/**
- * This interface allows clients to control how a command is executed
- * (e.g. dispatching the command to the UI thread).
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface CommandExecutor {
-
- /**
- * Execute the specified command.
- */
- void execute(Command command);
-
-
- /**
- * Straightforward implementation of the command executor interface
- * that simply executes the command without any sort of enhancement.
- */
- final class Default implements CommandExecutor {
- public static final CommandExecutor INSTANCE = new Default();
- public static CommandExecutor instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Default() {
- super();
- }
- public void execute(Command command) {
- command.execute();
- }
- @Override
- public String toString() {
- return "CommandExecutor.Default";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java
deleted file mode 100644
index ea1f5c68ea..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility;
-
-/**
- * Yet another level of indirection to allow clients to control
- * how a command is executed by the server
- * (e.g. dispatching the command to the UI thread).
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface CommandExecutorProvider {
-
- /**
- * Return the appropriate command executor.
- */
- CommandExecutor getCommandExecutor();
-
-
- /**
- * Straightforward implementation of the command executor provider
- * interface the returns the default command executor.
- */
- final class Default implements CommandExecutorProvider {
- public static final CommandExecutorProvider INSTANCE = new Default();
- public static CommandExecutorProvider instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Default() {
- super();
- }
- public CommandExecutor getCommandExecutor() {
- return CommandExecutor.Default.instance();
- }
- @Override
- public String toString() {
- return "CommandExecutorProvider.Default";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Filter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Filter.java
deleted file mode 100644
index 7b26b7f8ac..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/Filter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility;
-
-/**
- * Used by various "pluggable" classes to filter objects.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface Filter<T> {
-
- /**
- * Return whether the specified object is "accepted" by the
- * filter. The semantics of "accept" is determined by the
- * contract between the client and the server.
- */
- boolean accept(T o);
-
-
- final class Null<S> implements Filter<S> {
- @SuppressWarnings("unchecked")
- public static final Filter INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R> Filter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // nothing is filtered - everything is accepted
- public boolean accept(S next) {
- return true;
- }
- @Override
- public String toString() {
- return "Filter.Null"; //$NON-NLS-1$
- }
- }
-
- final class Disabled<S> implements Filter<S> {
- @SuppressWarnings("unchecked")
- public static final Filter INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> Filter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public boolean accept(S next) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "Filter.Disabled"; //$NON-NLS-1$
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/JavaType.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/JavaType.java
deleted file mode 100644
index 9347dbdf39..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/JavaType.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility;
-
-import java.io.PrintWriter;
-
-/**
- * This interface describes a Java type; i.e. its "element type"
- * and its "array depth". The element type is referenced by name,
- * allowing us to reference classes that are not (or cannot be) loaded.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- *
- * This interface is not intended to be implemented by clients.
- */
-public interface JavaType
- extends Comparable<JavaType>
-{
-
- /**
- * Return the name of the type's "element type".
- * A member type will have one or more '$' characters in its name.
- */
- String getElementTypeName();
-
- /**
- * Return the type's "array depth".
- */
- int getArrayDepth();
-
- boolean isArray();
-
- /**
- * NB: void.class.isPrimitive() == true
- */
- boolean isPrimitive();
-
- /**
- * NB: void.class.isPrimitive() == true
- */
- boolean isPrimitiveWrapper();
-
- /**
- * NB: variables cannot be declared 'void'
- */
- boolean isVariablePrimitive();
-
- /**
- * NB: variables cannot be declared 'void'
- */
- boolean isVariablePrimitiveWrapper();
-
- /**
- * Return the class corresponding to the type's element type and array depth.
- */
- Class<?> getJavaClass() throws ClassNotFoundException;
-
- /**
- * Return the version of the type's name that matches that
- * returned by java.lang.Class#getName()
- * (e.g. "[[J", "[Ljava.lang.Object;", "java.util.Map$Entry").
- */
- String getJavaClassName();
-
- boolean equals(String otherElementTypeName, int otherArrayDepth);
-
- boolean describes(String className);
-
- boolean describes(Class<?> javaClass);
-
- boolean equals(JavaType other);
-
- /**
- * Return the version of the type's name that can be used in source code:
- * "[[J" => "long[][]"
- * "java.util.Map$Entry" => "java.util.Map.Entry"
- */
- String declaration();
-
- /**
- * Append the version of the type's name that can be used in source code:
- * "[[J" => "long[][]"
- * "java.util.Map$Entry" => "java.util.Map.Entry"
- */
- void appendDeclarationTo(StringBuilder sb);
-
- /**
- * Print the version of the type's name that can be used in source code:
- * "[[J" => "long[][]"
- * "java.util.Map$Entry" => "java.util.Map.Entry"
- */
- void printDeclarationOn(PrintWriter pw);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java
deleted file mode 100644
index 08fcbc21d3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility;
-
-import java.io.PrintWriter;
-
-/**
- * This interface describes a Java method signature; i.e. its "name"
- * and its "parameter types". The parameter types are referenced by name,
- * allowing us to reference classes that are not (or cannot be) loaded.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- *
- * This interface is not intended to be implemented by clients.
- */
-public interface MethodSignature
- extends Comparable<MethodSignature>
-{
-
- /**
- * Return the method's name.
- */
- String getName();
-
- /**
- * Return the method's parameter types.
- */
- JavaType[] getParameterTypes();
-
- boolean equals(String otherName, JavaType[] otherParameterTypes);
-
- boolean equals(MethodSignature other);
-
- /**
- * Return a string representation of the method signature:
- * "foo(int, java.lang.String)"
- */
- String getSignature();
-
- /**
- * Append a string representation of the method signature:
- * "foo(int, java.lang.String)"
- */
- void appendSignatureTo(StringBuilder sb);
-
- /**
- * Print a string representation of the method signature:
- * "foo(int, java.lang.String)"
- */
- void printSignatureOn(PrintWriter pw);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AbstractAssociation.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AbstractAssociation.java
deleted file mode 100644
index 8ffa61d1d2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AbstractAssociation.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Implement some of the methods in Association that can
- * be defined in terms of the other methods.
- */
-public abstract class AbstractAssociation<K, V>
- implements Association<K, V>
-{
-
- /**
- * Default constructor.
- */
- protected AbstractAssociation() {
- super();
- }
-
- @Override
- public synchronized boolean equals(Object o) {
- if ( ! (o instanceof Association)) {
- return false;
- }
- Association<?, ?> other = (Association<?, ?>) o;
- return (this.key() == null ?
- other.key() == null : this.key().equals(other.key()))
- && (this.value() == null ?
- other.value() == null : this.value().equals(other.value()));
- }
-
- @Override
- public synchronized int hashCode() {
- return (this.key() == null ? 0 : this.key().hashCode())
- ^ (this.value() == null ? 0 : this.value().hashCode());
- }
-
- @Override
- public synchronized String toString() {
- return this.key() + " => " + this.value();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Association.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Association.java
deleted file mode 100644
index 03130e89be..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Association.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Straightforward definition of an object pairing.
- * The key is immutable.
- */
-public interface Association<K, V> {
-
- /**
- * Return the association's key.
- */
- K key();
-
- /**
- * Return the association's value.
- */
- V value();
-
- /**
- * Set the association's value.
- * Return the previous value.
- */
- V setValue(V value);
-
- /**
- * Return true if both the associations' keys and values
- * are equal.
- */
- boolean equals(Object o);
-
- /**
- * Return a hash code based on the association's
- * key and value.
- */
- int hashCode();
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Bag.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Bag.java
deleted file mode 100644
index b2c7223a40..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Bag.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-
-/**
- * A collection that allows duplicate elements.
- * <p>
- * The <code>Bag</code> interface places additional stipulations,
- * beyond those inherited from the <code>java.util.Collection</code> interface,
- * on the contracts of the <code>equals</code> and <code>hashCode</code> methods.
- *
- * @see HashBag
- */
-
-public interface Bag<E> extends java.util.Collection<E> {
-
- /**
- * Compares the specified object with this bag for equality. Returns
- * <code>true</code> if the specified object is also a bag, the two bags
- * have the same size, and every member of the specified bag is
- * contained in this bag with the same number of occurrences (or equivalently,
- * every member of this bag is contained in the specified bag with the same
- * number of occurrences). This definition ensures that the
- * equals method works properly across different implementations of the
- * bag interface.
- */
- boolean equals(Object o);
-
- /**
- * Returns the hash code value for this bag. The hash code of a bag is
- * defined to be the sum of the hash codes of the elements in the bag,
- * where the hashcode of a <code>null</code> element is defined to be zero.
- * This ensures that <code>b1.equals(b2)</code> implies that
- * <code>b1.hashCode() == b2.hashCode()</code> for any two bags
- * <code>b1</code> and <code>b2</code>, as required by the general
- * contract of the <code>Object.hashCode</code> method.
- */
- int hashCode();
-
- /**
- * Return the number of times the specified object occurs in the bag.
- */
- int count(Object o);
-
- /**
- * Add the specified object the specified number of times to the bag.
- */
- boolean add(E o, int count);
-
- /**
- * Remove the specified number of occurrences of the specified object
- * from the bag. Return whether the bag changed.
- */
- boolean remove(Object o, int count);
-
- /**
- * Return an iterator that returns each item in the bag
- * once and only once, irrespective of how many times
- * the item was added to the bag.
- */
- java.util.Iterator<E> uniqueIterator();
-
- /**
- * Return an iterator that returns an entry for each item in the bag
- * once and only once, irrespective of how many times
- * the item was added to the bag. The entry will indicate the item's
- * count.
- */
- java.util.Iterator<Entry<E>> entries();
-
-
- /**
- * A bag entry (element-count pair).
- * The <code>Bag.entries</code> method returns an iterator whose
- * elements are of this class. The <i>only</i> way to obtain a reference
- * to a bag entry is from the iterator returned by this method. These
- * <code>Bag.Entry</code> objects are valid <i>only</i> for the duration
- * of the iteration; more formally, the behavior of a bag entry is
- * undefined if the backing bag has been modified after the entry was
- * returned by the iterator, except through the <code>setCount</code>
- * operation on the bag entry.
- */
- interface Entry<E> {
-
- /**
- * Return the entry's element.
- */
- E getElement();
-
- /**
- * Return entry's count; i.e. the number of times the entry's element
- * occurs in the bag.
- * @see Bag#count(Object)
- */
- int getCount();
-
- /**
- * Set the entry's count; i.e. the number of times the entry's element
- * occurs in the bag. The new count must be a positive number.
- * Return the previous count of the entry's element.
- * NB: Use the iterator's <code>remove</code> method to set the
- * count to zero.
- */
- int setCount(int count);
-
- /**
- * Return whether the entry is equal to the specified object;
- * i.e. the specified object is a <code>Bag.Entry</code> and its
- * element and count are the same as the entry's.
- */
- boolean equals(Object obj);
-
- /**
- * Return the entry's hash code.
- */
- int hashCode();
-
- }
-
-
- final class Empty<E> extends AbstractCollection<E> implements Bag<E>, Serializable {
- @SuppressWarnings("unchecked")
- public static final Bag INSTANCE = new Empty();
- @SuppressWarnings("unchecked")
- public static <T> Bag<T> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Empty() {
- super();
- }
- @Override
- public Iterator<E> iterator() {
- return EmptyIterator.instance();
- }
- @Override
- public int size() {
- return 0;
- }
- public Iterator<E> uniqueIterator() {
- return EmptyIterator.instance();
- }
- public int count(Object o) {
- return 0;
- }
- public Iterator<Bag.Entry<E>> entries() {
- return EmptyIterator.instance();
- }
- public boolean remove(Object o, int count) {
- return false;
- }
- public boolean add(E o, int count) {
- throw new UnsupportedOperationException();
- }
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if ( ! (o instanceof Bag)) {
- return false;
- }
- return ((Bag<?>) o).size() == 0;
- }
- @Override
- public int hashCode() {
- return 0;
- }
- private static final long serialVersionUID = 1L;
- private Object readResolve() {
- return INSTANCE;
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiFilter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiFilter.java
deleted file mode 100644
index d102f9e267..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiFilter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import org.eclipse.jpt.utility.Filter;
-
-/**
- * Used by various "pluggable" classes to filter objects
- * in both directions.
- *
- * If anyone can come up with a better class name
- * and/or method name, I would love to hear it. ~bjv
- */
-public interface BidiFilter<T> extends Filter<T> {
-
- /**
- * Return whether the specified object is "accepted" by the
- * "reverse" filter. What that means is determined by the client.
- */
- boolean reverseAccept(T o);
-
-
- final class Null<S> implements BidiFilter<S> {
- @SuppressWarnings("unchecked")
- public static final BidiFilter INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R> BidiFilter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // nothing is filtered - everything is accepted
- public boolean accept(S next) {
- return true;
- }
- // nothing is "reverse-filtered" - everything is accepted
- public boolean reverseAccept(S o) {
- return true;
- }
- @Override
- public String toString() {
- return "BidiFilter.Null";
- }
- }
-
- final class Disabled<S> implements BidiFilter<S> {
- @SuppressWarnings("unchecked")
- public static final BidiFilter INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> BidiFilter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public boolean accept(S next) {
- throw new UnsupportedOperationException();
- }
- // throw an exception
- public boolean reverseAccept(S o) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "BidiFilter.Disabled";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiStringConverter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiStringConverter.java
deleted file mode 100644
index fcd8f4a311..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiStringConverter.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Used by various "pluggable" classes to transform objects
- * into strings and vice versa.
- *
- * If anyone can come up with a better class name
- * and/or method name, I would love to hear it. ~bjv
- */
-public interface BidiStringConverter<T> extends StringConverter<T> {
-
- /**
- * Convert the specified string into an object.
- * The semantics of "convert to object" is determined by the
- * contract between the client and the server.
- * Typically, if the string is null, null is returned.
- */
- T convertToObject(String s);
-
-
- final class Default<S> implements BidiStringConverter<S> {
- @SuppressWarnings("unchecked")
- public static final BidiStringConverter INSTANCE = new Default();
- @SuppressWarnings("unchecked")
- public static <R> BidiStringConverter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Default() {
- super();
- }
- // simply return the object's #toString() result
- public String convertToString(S o) {
- return (o == null) ? null : o.toString();
- }
- // simply return the string
- @SuppressWarnings("unchecked")
- public S convertToObject(String s) {
- return (S) s;
- }
- @Override
- public String toString() {
- return "BidiStringConverter.Default";
- }
- }
-
- final class Disabled<S> implements BidiStringConverter<S> {
- @SuppressWarnings("unchecked")
- public static final BidiStringConverter INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> BidiStringConverter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public String convertToString(S o) {
- throw new UnsupportedOperationException();
- }
- // throw an exception
- public S convertToObject(String s) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "BidiStringConverter.Disabled";
- }
- }
-
- final class BooleanConverter implements BidiStringConverter<Boolean> {
- public static final BidiStringConverter<Boolean> INSTANCE = new BooleanConverter();
- public static BidiStringConverter<Boolean> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private BooleanConverter() {
- super();
- }
- /** Return "true" if the Boolean is true, otherwise return "false". */
- public String convertToString(Boolean b) {
- return (b == null) ? null : b.toString();
- }
- /** Return Boolean.TRUE if the string is "true" (case-insensitive), otherwise return Boolean.FALSE. */
- public Boolean convertToObject(String s) {
- return (s == null) ? null : Boolean.valueOf(s);
- }
- @Override
- public String toString() {
- return "BidiStringConverter.BooleanConverter";
- }
- }
-
- final class IntegerConverter implements BidiStringConverter<Integer> {
- public static final BidiStringConverter<Integer> INSTANCE = new IntegerConverter();
- public static BidiStringConverter<Integer> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private IntegerConverter() {
- super();
- }
- /** Integer's #toString() works well. */
- public String convertToString(Integer integer) {
- return (integer == null) ? null : integer.toString();
- }
- /** Convert the string to an Integer, if possible. */
- public Integer convertToObject(String s) {
- return (s == null) ? null : Integer.valueOf(s);
- }
- @Override
- public String toString() {
- return "BidiStringConverter.IntegerConverter";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiTransformer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiTransformer.java
deleted file mode 100644
index 5f6d3d221b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BidiTransformer.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Used by various "pluggable" classes to transform objects
- * in both directions.
- *
- * If anyone can come up with a better class name
- * and/or method name, I would love to hear it. ~bjv
- */
-public interface BidiTransformer<T1, T2> extends Transformer<T1, T2> {
-
- /**
- * Return the "reverse-transformed" object.
- * The semantics of "reverse-transform" is determined by the
- * contract between the client and the server.
- */
- T1 reverseTransform(T2 o);
-
-
- final class Null<S1, S2> implements BidiTransformer<S1, S2> {
- @SuppressWarnings("unchecked")
- public static final BidiTransformer INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R1, R2> BidiTransformer<R1, R2> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // simply return the object, unchanged
- @SuppressWarnings("unchecked")
- public S2 transform(S1 o) {
- return (S2) o;
- }
- // simply return the object, unchanged
- @SuppressWarnings("unchecked")
- public S1 reverseTransform(S2 o) {
- return (S1) o;
- }
- @Override
- public String toString() {
- return "BidiTransformer.Null";
- }
- }
-
- final class Disabled<S1, S2> implements BidiTransformer<S1, S2> {
- @SuppressWarnings("unchecked")
- public static final BidiTransformer INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R1, R2> BidiTransformer<R1, R2> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public S2 transform(S1 o) {
- throw new UnsupportedOperationException();
- }
- // throw an exception
- public S1 reverseTransform(S2 o) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "BidiTransformer.Disabled";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BitTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BitTools.java
deleted file mode 100644
index 544f5bba82..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BitTools.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Assorted bit tools
- */
-public class BitTools {
-
- /**
- * Return whether the specified 'flags' has the specified
- * 'flagToCheck' set.
- */
- public static boolean flagIsSet(int flags, int flagToCheck) {
- return allFlagsAreSet(flags, flagToCheck);
- }
-
- /**
- * Return whether the specified 'flags' has the specified
- * 'flagToCheck' turned off.
- */
- public static boolean flagIsOff(int flags, int flagToCheck) {
- return allFlagsAreOff(flags, flagToCheck);
- }
-
- /**
- * Return whether the specified 'flags' has ONLY the specified
- * 'flagToCheck' set.
- */
- public static boolean onlyFlagIsSet(int flags, int flagToCheck) {
- return onlyFlagsAreSet(flags, flagToCheck);
- }
-
- /**
- * Return whether the specified 'flags' has ONLY the specified
- * 'flagToCheck' turned off.
- */
- public static boolean onlyFlagIsOff(int flags, int flagToCheck) {
- return onlyFlagsAreOff(flags, flagToCheck);
- }
-
- /**
- * Return whether the specified 'flags' has all the specified
- * 'flagsToCheck' set.
- */
- public static boolean allFlagsAreSet(int flags, int flagsToCheck) {
- return (flags & flagsToCheck) == flagsToCheck;
- }
-
- /**
- * Return whether the specified 'flags' has all the specified
- * 'flagsToCheck' turned off.
- */
- public static boolean allFlagsAreOff(int flags, int flagsToCheck) {
- return (flags & flagsToCheck) == 0;
- }
-
- /**
- * Return whether the specified 'flags' has ONLY the specified
- * 'flagsToCheck' set.
- */
- public static boolean onlyFlagsAreSet(int flags, int flagsToCheck) {
- return allFlagsAreSet(flags, flagsToCheck) && allFlagsAreOff(flags, ~flagsToCheck);
- }
-
- /**
- * Return whether the specified 'flags' has ONLY the specified
- * 'flagsToCheck' turned off.
- */
- public static boolean onlyFlagsAreOff(int flags, int flagsToCheck) {
- return allFlagsAreOff(flags, flagsToCheck) && allFlagsAreSet(flags, ~flagsToCheck);
- }
-
- /**
- * Return whether the specified 'flags' has any one of the specified
- * 'flagsToCheck' set.
- */
- public static boolean anyFlagsAreSet(int flags, int flagsToCheck) {
- return (flags & flagsToCheck) != 0;
- }
-
- /**
- * Return whether the specified 'flags' has any one of the specified
- * 'flagsToCheck' turned off.
- */
- public static boolean anyFlagsAreOff(int flags, int flagsToCheck) {
- return (flags & flagsToCheck) != flagsToCheck;
- }
-
- /**
- * Return whether the specified 'flags' has all the specified
- * 'flagsToCheck' set.
- */
- public static boolean allFlagsAreSet(int flags, int[] flagsToCheck) {
- for (int i = flagsToCheck.length; i-- > 0; ) {
- if ( ! allFlagsAreSet(flags, flagsToCheck[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified 'flags' has all the specified
- * 'flagsToCheck' turned off.
- */
- public static boolean allFlagsAreOff(int flags, int[] flagsToCheck) {
- for (int i = flagsToCheck.length; i-- > 0; ) {
- if ( ! allFlagsAreOff(flags, flagsToCheck[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified 'flags' has ONLY the specified
- * 'flagsToCheck' set.
- */
- public static boolean onlyFlagsAreSet(int flags, int[] flagsToCheck) {
- int combinedFlags = orFlags(flagsToCheck);
- return allFlagsAreSet(flags, combinedFlags) && allFlagsAreOff(flags, ~combinedFlags);
- }
-
- /**
- * Return whether the specified 'flags' has ONLY the specified
- * 'flagsToCheck' turned off.
- */
- public static boolean onlyFlagsAreOff(int flags, int[] flagsToCheck) {
- int combinedFlags = orFlags(flagsToCheck);
- return allFlagsAreOff(flags, combinedFlags) && allFlagsAreSet(flags, ~combinedFlags);
- }
-
- /**
- * Return whether the specified 'flags' has any one of the specified
- * 'flagsToCheck' set.
- */
- public static boolean anyFlagsAreSet(int flags, int[] flagsToCheck) {
- for (int i = flagsToCheck.length; i-- > 0; ) {
- if (anyFlagsAreSet(flags, flagsToCheck[i])) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified 'flags' has any one of the specified
- * 'flagsToCheck' turned off.
- */
- public static boolean anyFlagsAreOff(int flags, int[] flagsToCheck) {
- for (int i = flagsToCheck.length; i-- > 0; ) {
- if (anyFlagsAreOff(flags, flagsToCheck[i])) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * OR all the specified 'flags' together and return the result.
- */
- public static int orFlags(int[] flags) {
- int last = flags.length - 1;
- int result = flags[last];
- for (int i = last; i-- > 0; ) {
- result |= flags[i];
- }
- return result;
- }
-
- /**
- * AND all the specified 'flags' together and return the result.
- */
- public static int andFlags(int[] flags) {
- int last = flags.length - 1;
- int result = flags[last];
- for (int i = last; i-- > 0; ) {
- result &= flags[i];
- }
- return result;
- }
-
- /**
- * XOR all the specified 'flags' together and return the result.
- */
- public static int xorFlags(int[] flags) {
- int last = flags.length - 1;
- int result = flags[last];
- for (int i = last; i-- > 0; ) {
- result ^= flags[i];
- }
- return result;
- }
-
-
- // ********** constructor **********
-
- /**
- * Suppress default constructor, ensuring non-instantiability.
- */
- private BitTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BooleanHolder.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BooleanHolder.java
deleted file mode 100644
index e014e4eea1..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/BooleanHolder.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-
-/**
- * Provide a container for passing a flag that can be changed by the recipient.
- * @see SynchronizedBoolean
- */
-public class BooleanHolder
- implements Cloneable, Serializable
-{
- /** Backing boolean. */
- private boolean value;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Create a boolean holder with the specified initial value.
- */
- public BooleanHolder(boolean value) {
- super();
- this.value = value;
- }
-
- /**
- * Create a boolean holder with an initial value of false.
- */
- public BooleanHolder() {
- this(false);
- }
-
-
- // ********** accessors **********
-
- /**
- * Return the current boolean value.
- */
- public boolean getValue() {
- return this.value;
- }
-
- /**
- * Return whether the current boolean value is true.
- */
- public boolean isTrue() {
- return this.value;
- }
-
- /**
- * Return whether the current boolean value is false.
- */
- public boolean isFalse() {
- return ! this.value;
- }
-
- /**
- * Return whether the current boolean value is the specified value.
- */
- public boolean is(boolean v) {
- return this.value == v;
- }
-
- /**
- * Set the boolean value.
- */
- public void setValue(boolean value) {
- this.value = value;
- }
-
- /**
- * Set the boolean value to true.
- */
- public void setTrue() {
- this.value = true;
- }
-
- /**
- * Set the boolean value to false.
- */
- public void setFalse() {
- this.value = false;
- }
-
-
- // ********** standard methods **********
-
- @Override
- public Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof BooleanHolder) {
- return this.value == ((BooleanHolder) o).value;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return this.value ? 1 : 0;
- }
-
- @Override
- public String toString() {
- return '[' + String.valueOf(this.value) + ']';
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java
deleted file mode 100644
index a09dc39b06..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ClassTools.java
+++ /dev/null
@@ -1,1678 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.Stack;
-
-/**
- * Convenience methods related to the java.lang.reflect package.
- * These methods provide shortcuts for manipulating objects via
- * reflection; particularly when dealing with fields and/or methods that
- * are not publicly accessible or are inherited.
- *
- * In most cases, all the exceptions are handled and
- * wrapped in java.lang.RuntimeExceptions; so these methods should
- * be used when you are confident that you will not having any problems
- * using reflection.
- *
- * There are also a number of methods whose names
- * begin with "attempt". These methods will throw a NoSuchMethodException
- * or NoSuchFieldException when appropriate, allowing you to probe
- * for methods that should be present but might not.
- */
-public final class ClassTools {
-
- public static final Class<?>[] ZERO_PARAMETER_TYPES = new Class[0];
- public static final Object[] ZERO_PARAMETERS = new Object[0];
- private static final String CR = StringTools.CR;
-
- public static final char NESTED_CLASS_NAME_SEPARATOR = '$';
-
- public static final char ARRAY_INDICATOR = '[';
- public static final char TYPE_DECLARATION_ARRAY_OPEN = '[';
- public static final char TYPE_DECLARATION_ARRAY_CLOSE = ']';
-
- public static final char REFERENCE_CLASS_CODE = 'L';
- public static final char REFERENCE_CLASS_NAME_DELIMITER = ';';
-
- private static Primitive[] PRIMITIVES; // pseudo-'final' - lazy-initialized
- public static final char BYTE_CODE = 'B';
- public static final char CHAR_CODE = 'C';
- public static final char DOUBLE_CODE = 'D';
- public static final char FLOAT_CODE = 'F';
- public static final char INT_CODE = 'I';
- public static final char LONG_CODE = 'J';
- public static final char SHORT_CODE = 'S';
- public static final char BOOLEAN_CODE = 'Z';
- public static final char VOID_CODE = 'V';
- private static int MAX_PRIMITIVE_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized
- private static int MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized
-
- public static final String VOID_CLASS_NAME = void.class.getName();
- public static final String VOID_WRAPPER_CLASS_NAME = java.lang.Void.class.getName();
-
-
- /**
- * Return all the fields for the
- * specified class, including inherited fields.
- * Class#allFields()
- */
- public static Field[] allFields(Class<?> javaClass) {
- Stack<Field> stack = new Stack<Field>();
- for (Class<?> tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) {
- pushDeclaredFields(tempClass, stack);
- }
- Collections.reverse(stack);
- return stack.toArray(new Field[stack.size()]);
- }
-
- /**
- * Return all the methods for the
- * specified class, including inherited methods.
- * Class#allMethods()
- */
- public static Method[] allMethods(Class<?> javaClass) {
- Stack<Method> stack = new Stack<Method>();
- for (Class<?> tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) {
- pushDeclaredMethods(tempClass, stack);
- }
- Collections.reverse(stack);
- return stack.toArray(new Method[stack.size()]);
- }
-
- /**
- * Convenience method.
- * Return a new instance of the specified class,
- * using the class's default (zero-argument) constructor.
- * Throw an exception if the default constructor is not defined.
- * Class#newInstance() throws NoSuchMethodException
- */
- public static <T> T attemptNewInstance(Class<T> javaClass) throws NoSuchMethodException {
- return attemptNewInstance(javaClass, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Return a new instance of the specified class,
- * given the constructor parameter types and parameters.
- * Throw an exception if the constructor is not defined.
- * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException
- */
- public static <T> T attemptNewInstance(Class<T> javaClass, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException {
- try {
- return constructor(javaClass, parameterTypes).newInstance(parameters);
- } catch (InstantiationException ie) {
- throw new RuntimeException(ie + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), ie);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), iae);
- } catch (InvocationTargetException ite) {
- throw new RuntimeException(fullyQualifiedConstructorSignature(javaClass, parameterTypes) + CR + ite.getTargetException(), ite);
- }
- }
-
- /**
- * Convenience method.
- * Return a new instance of the specified class,
- * given the constructor parameter type and parameter.
- * Throw an exception if the constructor is not defined.
- * Class#newInstance(Class<?> parameterType, Object parameter) throws NoSuchMethodException
- */
- public static <T> T attemptNewInstance(Class<T> javaClass, Class<?> parameterType, Object parameter) throws NoSuchMethodException {
- return attemptNewInstance(javaClass, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Attempt to get a field value, given the containing object and field name.
- * Return its result.
- * Useful for accessing private, package, or protected fields.
- * Throw an exception if the field is not defined.
- * Object#getFieldValue(String fieldName) throws NoSuchFieldException
- */
- public static Object attemptToGetFieldValue(Object object, String fieldName) throws NoSuchFieldException {
- try {
- return field(object, fieldName).get(object);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + fullyQualifiedFieldName(object, fieldName), iae);
- }
- }
-
- /**
- * Attempt to get a static field value, given the containing object and field name.
- * Return its result.
- * Useful for accessing private, package, or protected fields.
- * Throw an exception if the field is not defined.
- * Class#getStaticFieldValue(String fieldName) throws NoSuchFieldException
- */
- public static Object attemptToGetStaticFieldValue(Class<?> javaClass, String fieldName) throws NoSuchFieldException {
- try {
- return field(javaClass, fieldName).get(null);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + fullyQualifiedFieldName(javaClass, fieldName), iae);
- }
- }
-
- /**
- * Convenience method.
- * Attempt to execute a zero-argument method,
- * given the receiver and method name.
- * Return its result.
- * Throw an exception if the method is not found.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName) throws NoSuchMethodException
- */
- public static Object attemptToExecuteMethod(Object receiver, String methodName) throws NoSuchMethodException {
- return attemptToExecuteMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Convenience method.
- * Attempt to execute a method, given the receiver,
- * method name, parameter type, and parameter.
- * Return its result.
- * Throw an exception if the method is not found.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException
- */
- public static Object attemptToExecuteMethod(Object receiver, String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException {
- return attemptToExecuteMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Attempt to execute a method, given the receiver,
- * method name, parameter types, and parameters.
- * Return its result.
- * Throw an exception if the method is not found.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException
- */
- public static Object attemptToExecuteMethod(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException {
- return executeMethod(method(receiver, methodName, parameterTypes), receiver, parameters);
- }
-
- /**
- * Attempt to execute a method, given the receiver,
- * method name, parameter types, and parameters.
- * Return its result.
- * Throw an exception if the method is not found.
- * If the executed method throws an exception, rethrow that exception.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException
- */
- public static Object attemptToExecuteMethodWithException(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters)
- throws Throwable, NoSuchMethodException
- {
- return executeMethodWithException(method(receiver, methodName, parameterTypes), receiver, parameters);
- }
-
- /**
- * Convenience method.
- * Attempt to execute a zero-argument static method,
- * given the class and method name.
- * Return its result.
- * Throw an exception if the method is not found.
- * Useful for invoking private, package, or protected methods.
- * Class#executeStaticMethod(String methodName) throws NoSuchMethodException
- */
- public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName) throws NoSuchMethodException {
- return attemptToExecuteStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Attempt to execute a static method, given the class,
- * method name, parameter types, and parameters.
- * Return its result.
- * Throw an exception if the method is not found.
- * Useful for invoking private, package, or protected methods.
- * Class#executeStaticMethod(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException
- */
- public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException {
- return executeStaticMethod(staticMethod(javaClass, methodName, parameterTypes), parameters);
- }
-
- /**
- * Convenience method.
- * Attempt to execute a static method, given the class,
- * method name, parameter type, and parameter.
- * Return its result.
- * Throw an exception if the method is not found.
- * Useful for invoking private, package, or protected methods.
- * Class#executeStaticMethod(String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException
- */
- public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException {
- return attemptToExecuteStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Attempt to set a field value, given the
- * containing object, field name, and new field value.
- * Useful for accessing private, package, or protected fields.
- * Throw an exception if the field is not defined.
- * Object#setFieldValue(String fieldName, Object fieldValue) throws NoSuchFieldException
- */
- public static void attemptToSetFieldValue(Object object, String fieldName, Object fieldValue) throws NoSuchFieldException {
- try {
- field(object, fieldName).set(object, fieldValue);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + fullyQualifiedFieldName(object, fieldName), iae);
- }
- }
-
- /**
- * Attempt to set a static field value, given the
- * containing class, field name, and new field value.
- * Useful for accessing private, package, or protected fields.
- * Throw an exception if the field is not defined.
- * Class#setStaticFieldValue(String fieldName, Object fieldValue) throws NoSuchFieldException
- */
- public static void attemptToSetStaticFieldValue(Class<?> javaClass, String fieldName, Object fieldValue) throws NoSuchFieldException {
- try {
- field(javaClass, fieldName).set(null, fieldValue);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + fullyQualifiedFieldName(javaClass, fieldName), iae);
- }
- }
-
- /**
- * Convenience method.
- * Return the default (zero-argument) constructor
- * for the specified class.
- * Set accessible to true, so we can access
- * private/package/protected constructors.
- * Class#constructor() throws NoSuchMethodException
- */
- public static <T> Constructor<T> constructor(Class<T> javaClass) throws NoSuchMethodException {
- return constructor(javaClass, ZERO_PARAMETER_TYPES);
- }
-
- /**
- * Return the constructor for the specified class
- * and formal parameter types.
- * Set accessible to true, so we can access
- * private/package/protected constructors.
- * Class#constructor(Class<?>[] parameterTypes) throws NoSuchMethodException
- */
- public static <T> Constructor<T> constructor(Class<T> javaClass, Class<?>[] parameterTypes) throws NoSuchMethodException {
- Constructor<T> constructor = javaClass.getDeclaredConstructor(parameterTypes);
- constructor.setAccessible(true);
- return constructor;
- }
-
- /**
- * Convenience method.
- * Return the constructor for the specified class
- * and formal parameter type.
- * Set accessible to true, so we can access
- * private/package/protected constructors.
- * Class#constructor(Class<?> parameterType) throws NoSuchMethodException
- */
- public static <T> Constructor<T> constructor(Class<T> javaClass, Class<?> parameterType) throws NoSuchMethodException {
- return constructor(javaClass, new Class[] {parameterType});
- }
-
- /**
- * Return the declared fields for the specified class.
- * Set accessible to true, so we can access
- * private/package/protected fields.
- * Class#accessibleDeclaredFields()
- */
- public static Field[] declaredFields(Class<?> javaClass) {
- Field[] fields = javaClass.getDeclaredFields();
- for (Field field : fields) {
- field.setAccessible(true);
- }
- return fields;
- }
-
- /**
- * Return the declared methods for the
- * specified class.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- * Class#accessibleDeclaredMethods()
- */
- public static Method[] declaredMethods(Class<?> javaClass) {
- Method[] methods = javaClass.getDeclaredMethods();
- for (Method method : methods) {
- method.setAccessible(true);
- }
- return methods;
- }
-
- /**
- * Return the default (zero-argument) constructor
- * for the specified class.
- * Set accessible to true, so we can access
- * private/package/protected constructors.
- * Class#defaultConstructor()
- */
- public static <T> Constructor<T> defaultConstructor(Class<T> javaClass) throws NoSuchMethodException {
- return constructor(javaClass);
- }
-
- /**
- * Return a field for the specified class and field name.
- * If the class does not directly
- * define the field, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected fields.
- */
- public static Field field(Class<?> javaClass, String fieldName) throws NoSuchFieldException {
- Field field = null;
- try {
- field = javaClass.getDeclaredField(fieldName);
- } catch (NoSuchFieldException ex) {
- Class<?> superclass = javaClass.getSuperclass();
- if (superclass == null) {
- throw ex;
- }
- // recurse
- return field(superclass, fieldName);
- }
- field.setAccessible(true);
- return field;
- }
-
- /**
- * Convenience method.
- * Return a field for the specified object and field name.
- * If the object's class does not directly
- * define the field, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected fields.
- */
- public static Field field(Object object, String fieldName) throws NoSuchFieldException {
- return field(object.getClass(), fieldName);
- }
-
- /*
- * Return a string representation of the specified constructor.
- */
- private static String fullyQualifiedConstructorSignature(Class<?> javaClass, Class<?>[] parameterTypes) {
- return fullyQualifiedMethodSignature(javaClass, null, parameterTypes);
- }
-
- /*
- * Return a string representation of the specified field.
- */
- private static String fullyQualifiedFieldName(Class<?> javaClass, String fieldName) {
- StringBuilder sb = new StringBuilder(200);
- sb.append(javaClass.getName());
- sb.append('.');
- sb.append(fieldName);
- return sb.toString();
- }
-
- /*
- * Return a string representation of the specified field.
- */
- private static String fullyQualifiedFieldName(Object object, String fieldName) {
- return fullyQualifiedFieldName(object.getClass(), fieldName);
- }
-
- /*
- * Return a string representation of the specified method.
- */
- private static String fullyQualifiedMethodSignature(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) {
- StringBuilder sb = new StringBuilder(200);
- sb.append(javaClass.getName());
- // this check allows us to use this code for constructors, where the methodName is null
- if (methodName != null) {
- sb.append('.');
- sb.append(methodName);
- }
- sb.append('(');
- int max = parameterTypes.length - 1;
- if (max != -1) {
- // stop one short of the end of the array
- for (int i = 0; i < max; i++) {
- sb.append(parameterTypes[i].getName());
- sb.append(", "); //$NON-NLS-1$
- }
- sb.append(parameterTypes[max].getName());
- }
- sb.append(')');
- return sb.toString();
- }
-
- /*
- * Return a string representation of the specified method.
- */
- private static String fullyQualifiedMethodSignature(Object receiver, String methodName, Class<?>[] parameterTypes) {
- return fullyQualifiedMethodSignature(receiver.getClass(), methodName, parameterTypes);
- }
-
- /**
- * Get a field value, given the containing object and field name.
- * Return its result.
- * Useful for accessing private, package, or protected fields.
- * Object#getFieldValue(String fieldName)
- */
- public static Object fieldValue(Object object, String fieldName) {
- try {
- return attemptToGetFieldValue(object, fieldName);
- } catch (NoSuchFieldException nsfe) {
- throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(object, fieldName), nsfe);
- }
- }
-
- /**
- * Get a static field value, given the containing class and field name.
- * Return its result.
- * Useful for accessing private, package, or protected fields.
- * Class#getStaticFieldValue(String fieldName)
- */
- public static Object staticFieldValue(Class<?> javaClass, String fieldName) {
- try {
- return attemptToGetStaticFieldValue(javaClass, fieldName);
- } catch (NoSuchFieldException nsfe) {
- throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe);
- }
- }
-
- /**
- * Convenience method.
- * Execute a zero-argument method, given the receiver and method name.
- * Return its result.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName)
- */
- public static Object executeMethod(Object receiver, String methodName) {
- return executeMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Execute a method, given the receiver,
- * method name, parameter types, and parameters.
- * Return its result.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters)
- */
- public static Object executeMethod(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) {
- try {
- return attemptToExecuteMethod(receiver, methodName, parameterTypes, parameters);
- } catch (NoSuchMethodException nsme) {
- throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme);
- }
- }
-
- /**
- * Convenience method.
- * Execute a one-argument method, given the receiver,
- * method name, parameter type, and parameter.
- * Return its result.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?> parameterType, Object parameter)
- */
- public static Object executeMethod(Object receiver, String methodName, Class<?> parameterType, Object parameter) {
- return executeMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Convenience method.
- * Execute a zero-argument method, given the receiver and method name.
- * Return its result.
- * If the method throws an exception, rethrow that exception.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName)
- */
- public static Object executeMethodWithException(Object receiver, String methodName)
- throws Throwable
- {
- return executeMethodWithException(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Convenience method.
- * Execute a one-argument method, given the receiver,
- * method name, parameter type, and parameter.
- * Return its result.
- * If the method throws an exception, rethrow that exception.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?> parameterType, Object parameter)
- */
- public static Object executeMethodWithException(Object receiver, String methodName, Class<?> parameterType, Object parameter)
- throws Throwable
- {
- return executeMethodWithException(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Execute a method, given the receiver,
- * method name, parameter types, and parameters.
- * Return its result.
- * If the method throws an exception, rethrow that exception.
- * Useful for invoking private, package, or protected methods.
- * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters)
- */
- public static Object executeMethodWithException(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters)
- throws Throwable
- {
- try {
- return attemptToExecuteMethodWithException(receiver, methodName, parameterTypes, parameters);
- } catch (NoSuchMethodException nsme) {
- throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme);
- }
- }
-
- /**
- * Execute the specified method with the specified parameters.
- * Return its result.
- * Convert exceptions to RuntimeExceptions.
- */
- public static Object executeMethod(Method method, Object receiver, Object[] parameters) {
- try {
- return method.invoke(receiver, parameters);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + method, iae);
- } catch (InvocationTargetException ite) {
- throw new RuntimeException(method + CR + ite.getTargetException(), ite);
- }
- }
-
- /**
- * Execute the specified method with the specified parameters.
- * Return its result.
- * If the method throws an exception, rethrow that exception.
- * Convert all other exceptions to RuntimeExceptions.
- */
- public static Object executeMethodWithException(Method method, Object receiver, Object[] parameters)
- throws Throwable
- {
- try {
- return method.invoke(receiver, parameters);
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae + CR + method, iae);
- } catch (InvocationTargetException ite) {
- Throwable cause = ite.getCause();
- if (cause == null) {
- throw new RuntimeException(method.toString(), ite);
- }
- throw cause;
- }
- }
-
- /**
- * Convenience method.
- * Execute a zero-argument static method,
- * given the class and method name.
- * Return its result.
- * Useful for invoking private, package, or protected methods.
- * Class#executeStaticMethod(String methodName)
- */
- public static Object executeStaticMethod(Class<?> javaClass, String methodName) {
- return executeStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Execute a static method, given the class,
- * method name, parameter types, and parameters.
- * Return its result.
- * Useful for invoking private, package, or protected methods.
- * Class#executeStaticMethod(String methodName, Class<?>[] parameterTypes, Object[] parameters)
- */
- public static Object executeStaticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes, Object[] parameters) {
- try {
- return attemptToExecuteStaticMethod(javaClass, methodName, parameterTypes, parameters);
- } catch (NoSuchMethodException nsme) {
- throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes), nsme);
- }
- }
-
- /**
- * Convenience method.
- * Execute a static method, given the class,
- * method name, parameter type, and parameter.
- * Return its result.
- * Useful for invoking private, package, or protected methods.
- * Class#executeStaticMethod(String methodName, Class<?> parameterType, Object parameter)
- */
- public static Object executeStaticMethod(Class<?> javaClass, String methodName, Class<?> parameterType, Object parameter) {
- return executeStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Execute the specified static method with the specified parameters.
- * Return its result.
- * Convert exceptions to RuntimeExceptions.
- */
- public static Object executeStaticMethod(Method method, Object[] parameters) {
- return executeMethod(method, null, parameters);
- }
-
- /**
- * Convenience method.
- * Return a zero-argument method for the specified class
- * and method name. If the class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method method(Class<?> javaClass, String methodName) throws NoSuchMethodException {
- return method(javaClass, methodName, ZERO_PARAMETER_TYPES);
- }
-
- /**
- * Return a method for the specified class, method name,
- * and formal parameter types. If the class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method method(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException {
- Method method = null;
- try {
- method = javaClass.getDeclaredMethod(methodName, parameterTypes);
- } catch (NoSuchMethodException ex) {
- Class<?> superclass = javaClass.getSuperclass();
- if (superclass == null) {
- throw ex;
- }
- // recurse
- return method(superclass, methodName, parameterTypes);
- }
- method.setAccessible(true);
- return method;
- }
-
- /**
- * Convenience method.
- * Return a method for the specified class, method name,
- * and formal parameter type. If the class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method method(Class<?> javaClass, String methodName, Class<?> parameterType) throws NoSuchMethodException {
- return method(javaClass, methodName, new Class[] {parameterType});
- }
-
- /**
- * Convenience method.
- * Return a zero-argument method for the specified object
- * and method name. If the object's class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method method(Object object, String methodName) throws NoSuchMethodException {
- return method(object.getClass(), methodName);
- }
-
- /**
- * Convenience method.
- * Return a method for the specified object, method name,
- * and formal parameter types. If the object's class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method method(Object object, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException {
- return method(object.getClass(), methodName, parameterTypes);
- }
-
- /**
- * Convenience method.
- * Return a method for the specified object, method name,
- * and formal parameter type. If the object's class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method method(Object object, String methodName, Class<?> parameterType) throws NoSuchMethodException {
- return method(object.getClass(), methodName, parameterType);
- }
-
- /**
- * Convenience method.
- * Return the specified class (without the checked exception).
- */
- public static Class<?> classForName(String className) {
- try {
- return Class.forName(className);
- } catch (ClassNotFoundException ex) {
- throw new RuntimeException(className, ex);
- }
- }
-
- /**
- * Convenience method.
- * Return a new instance of the specified class,
- * using the class's default (zero-argument) constructor.
- * Class#newInstance()
- */
- public static <T> T newInstance(Class<T> javaClass) {
- return newInstance(javaClass, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS);
- }
-
- /**
- * Convenience method.
- * Return a new instance of the specified class,
- * using the class's default (zero-argument) constructor.
- * Class#newInstance()
- */
- public static Object newInstance(String className) throws ClassNotFoundException {
- return newInstance(className, null);
- }
-
- /**
- * Convenience method.
- * Return a new instance of the specified class,
- * using the class's default (zero-argument) constructor.
- * Class#newInstance()
- */
- public static Object newInstance(String className, ClassLoader classLoader) throws ClassNotFoundException {
- return newInstance(Class.forName(className, true, classLoader));
- }
-
- /**
- * Return a new instance of the specified class,
- * given the constructor parameter types and parameters.
- * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters)
- */
- public static <T> T newInstance(Class<T> javaClass, Class<?>[] parameterTypes, Object[] parameters) {
- try {
- return attemptNewInstance(javaClass, parameterTypes, parameters);
- } catch (NoSuchMethodException nsme) {
- throw new RuntimeException(nsme + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), nsme);
- }
- }
-
- /**
- * Return a new instance of the specified class,
- * given the constructor parameter types and parameters.
- * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters)
- */
- public static Object newInstance(String className, Class<?>[] parameterTypes, Object[] parameters) throws ClassNotFoundException {
- return newInstance(className, parameterTypes, parameters, null);
- }
-
- /**
- * Return a new instance of the specified class,
- * given the constructor parameter types and parameters.
- * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters)
- */
- public static Object newInstance(String className, Class<?>[] parameterTypes, Object[] parameters, ClassLoader classLoader) throws ClassNotFoundException {
- return newInstance(Class.forName(className, true, classLoader), parameterTypes, parameters);
- }
-
- /**
- * Convenience method.
- * Return a new instance of the specified class,
- * given the constructor parameter type and parameter.
- * Class#newInstance(Class<?> parameterType, Object parameter)
- */
- public static <T> T newInstance(Class<T> javaClass, Class<?> parameterType, Object parameter) {
- return newInstance(javaClass, new Class[] {parameterType}, new Object[] {parameter});
- }
-
- /**
- * Return a new instance of the specified class,
- * given the constructor parameter type and parameter.
- * Class#newInstance(Class<?> parameterType, Object parameter)
- */
- public static Object newInstance(String className, Class<?> parameterType, Object parameter) throws ClassNotFoundException {
- return newInstance(className, parameterType, parameter, null);
- }
-
- /**
- * Return a new instance of the specified class,
- * given the constructor parameter type and parameter.
- * Class#newInstance(Class<?> parameterType, Object parameter)
- */
- public static Object newInstance(String className, Class<?> parameterType, Object parameter, ClassLoader classLoader) throws ClassNotFoundException {
- return newInstance(Class.forName(className, false, classLoader), parameterType, parameter);
- }
-
- /*
- * Push the declared fields for the specified class
- * onto the top of the stack.
- */
- private static void pushDeclaredFields(Class<?> javaClass, Stack<Field> stack) {
- Field[] fields = declaredFields(javaClass);
- for (int i = fields.length; i-- > 0; ) {
- stack.push(fields[i]);
- }
- }
-
- /*
- * Push the declared methods for the specified class
- * onto the top of the stack.
- */
- private static void pushDeclaredMethods(Class<?> javaClass, Stack<Method> stack) {
- Method[] methods = declaredMethods(javaClass);
- for (int i = methods.length; i-- > 0; ) {
- stack.push(methods[i]);
- }
- }
-
- /**
- * Set a field value, given the containing object, field name, and new field value.
- * Useful for accessing private, package, or protected fields.
- * Object#setFieldValue(String fieldName, Object fieldValue)
- */
- public static void setFieldValue(Object object, String fieldName, Object fieldValue) {
- try {
- attemptToSetFieldValue(object, fieldName, fieldValue);
- } catch (NoSuchFieldException nsfe) {
- throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(object, fieldName), nsfe);
- }
- }
-
- /**
- * Set a static field value, given the containing class, field name, and new field value.
- * Useful for accessing private, package, or protected fields.
- * Class#setStaticFieldValue(String fieldName, Object fieldValue)
- */
- public static void setStaticFieldValue(Class<?> javaClass, String fieldName, Object fieldValue) {
- try {
- attemptToSetStaticFieldValue(javaClass, fieldName, fieldValue);
- } catch (NoSuchFieldException nsfe) {
- throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe);
- }
- }
-
- /**
- * Return the short name of the object's class.
- * Class#getShortName()
- */
- public static String shortClassNameForObject(Object object) {
- return shortNameFor(object.getClass());
- }
-
- /**
- * Return the short name of the class (e.g. "Object").
- * Class#getShortName()
- */
- public static String shortNameForClassNamed(String className) {
- return className.substring(className.lastIndexOf('.') + 1);
- }
-
- /**
- * Return the short name of the class (e.g. "Object").
- * Class#getShortName()
- */
- public static String shortNameFor(Class<?> javaClass) {
- return shortNameForClassNamed(javaClass.getName());
- }
-
- /**
- * Return the nested name of the object's class.
- * Class#getNestedName()
- */
- public static String nestedClassNameForObject(Object object) {
- return nestedNameFor(object.getClass());
- }
-
- /**
- * Return the nested name of the class (e.g. "Entry").
- * Class#getNestedName()
- */
- public static String nestedNameForClassNamed(String className) {
- return className.substring(className.lastIndexOf(NESTED_CLASS_NAME_SEPARATOR) + 1);
- }
-
- /**
- * Return the nested name of the class (e.g. "Entry").
- * Class#getNestedName()
- */
- public static String nestedNameFor(Class<?> javaClass) {
- return nestedNameForClassNamed(javaClass.getName());
- }
-
- /**
- * Return the "toString()" name of the object's class.
- */
- public static String toStringClassNameForObject(Object object) {
- return toStringNameFor(object.getClass());
- }
-
- /**
- * Return the "toString()" name of the class.
- * "Member" classes will return only the final name:
- * "com.foo.bar.TopLevelClass$MemberClass$NestedMemberClass"
- * => "NestedMemberClass"
- * "Local" and "anonymous" classes will still return the embedded '$'s:
- * "com.foo.bar.TopLevelClass$1LocalClass"
- * => "TopLevelClass$1LocalClass"
- * "com.foo.bar.TopLevelClass$1"
- * => "TopLevelClass$1"
- */
- public static String toStringNameForClassNamed(String className) {
- return classNamedIsMember(className) ?
- className.substring(className.lastIndexOf(NESTED_CLASS_NAME_SEPARATOR) + 1)
- :
- className.substring(className.lastIndexOf('.') + 1);
- }
-
- /**
- * Return the "toString()" name of the class.
- */
- public static String toStringNameFor(Class<?> javaClass) {
- return toStringNameForClassNamed(javaClass.getName());
- }
-
- /**
- * Return the package name of the class (e.g. "java.lang").
- * Class#getPackageName()
- */
- public static String packageNameFor(Class<?> javaClass) {
- return packageNameForClassNamed(javaClass.getName());
- }
-
- /**
- * Return the package name of the class (e.g. "java.lang").
- * Class#getPackageName()
- */
- public static String packageNameForClassNamed(String className) {
- int lastPeriod = className.lastIndexOf('.');
- if (lastPeriod == -1) {
- return ""; //$NON-NLS-1$
- }
- return className.substring(0, lastPeriod);
- }
-
- /**
- * Return the short name of the class,
- * followed by its package name (e.g. "Object (java.lang)").
- * Class#getShortNameWithPackage()
- */
- public static String shortNameWithPackage(Class<?> javaClass) {
- StringBuilder sb = new StringBuilder(200);
- sb.append(shortNameFor(javaClass));
- if ( ! javaClass.isPrimitive()) {
- sb.append(" ("); //$NON-NLS-1$
- sb.append(packageNameFor(javaClass));
- sb.append(')');
- }
- return sb.toString();
- }
-
- /**
- * Convenience method.
- * Return a zero-argument, static method for the specified class
- * and method name. If the class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method staticMethod(Class<?> javaClass, String methodName) throws NoSuchMethodException {
- return staticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES);
- }
-
- /**
- * Return a static method for the specified class, method name,
- * and formal parameter types. If the class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method staticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException {
- Method method = method(javaClass, methodName, parameterTypes);
- if (Modifier.isStatic(method.getModifiers())) {
- return method;
- }
- throw new NoSuchMethodException(fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes));
- }
-
- /**
- * Convenience method.
- * Return a static method for the specified class, method name,
- * and formal parameter type. If the class does not directly
- * implement the method, look for it in the class's superclasses.
- * Set accessible to true, so we can access
- * private/package/protected methods.
- */
- public static Method staticMethod(Class<?> javaClass, String methodName, Class<?> parameterTypes) throws NoSuchMethodException {
- return staticMethod(javaClass, methodName, new Class[] {parameterTypes});
- }
-
- /**
- * Return whether the specified class can be "declared" in code;
- * i.e. it is either a "top-level" class or a "member" class, but it
- * is not an "array" class. This method rolls together all the checks
- * from the other methods for a bit of a performance tweak.
- * Class#isDeclarable()
- */
- public static boolean classNamedIsDeclarable(String className) {
- if (className.charAt(0) == ARRAY_INDICATOR) {
- return false; // it is an "array" class
- }
- int index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR);
- if (index == -1) {
- return true; // it is a "top-level" class
- }
- do {
- // the character immediately after each dollar sign cannot be a digit
- index++;
- if (Character.isDigit(className.charAt(index))) {
- return false;
- }
- index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR, index);
- } while (index != -1);
- return true;
- }
-
- /**
- * Return whether the specified class is a "top-level" class,
- * as opposed to a "member", "local", or "anonymous" class,
- * using the standard jdk naming conventions (i.e. the class
- * name does NOT contain a '$': "TopLevelClass").
- * Class#isTopLevel()
- */
- public static boolean classNamedIsTopLevel(String className) {
- if (classNamedIsArray(className)) {
- return false;
- }
- return className.indexOf(NESTED_CLASS_NAME_SEPARATOR) == -1;
- }
-
- /**
- * Return whether the specified class is a "member" class,
- * as opposed to a "top-level", "local", or "anonymous" class,
- * using the standard jdk naming conventions (i.e. the class
- * name contains at least one '$' and all the names between
- * each '$' are legal class names:
- * "TopLevelClass$MemberClass$NestedMemberClass").
- * Class#isMember()
- */
- public static boolean classNamedIsMember(String className) {
- if (classNamedIsArray(className)) {
- return false;
- }
- int index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR);
- if (index == -1) {
- return false; // it is a "top-level" class
- }
- do {
- // the character immediately after each dollar sign cannot be a digit
- index++;
- if (Character.isDigit(className.charAt(index))) {
- return false;
- }
- index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR, index);
- } while (index != -1);
- return true;
- }
-
- /**
- * Return whether the specified class is a "local" class,
- * as opposed to a "top-level", "member", or "anonymous" class,
- * using the standard jdk (or Eclipse) naming conventions.
- * In the jdk, the class name ends with '$nnnXXX' where the '$' is
- * followed by a series of numeric digits which are followed by the
- * local class name: "TopLevelClass$1LocalClass".
- * In Eclipse, the class name ends with '$nnn$XXX' where the '$' is
- * followed by a series of numeric digits which are separated from
- * the local class name by another '$': "TopLevelClass$1$LocalClass".
- * Class#isLocal()
- */
- public static boolean classNamedIsLocal(String className) {
- if (classNamedIsArray(className)) {
- return false;
- }
- int dollar = className.indexOf(NESTED_CLASS_NAME_SEPARATOR);
- if (dollar == -1) {
- return false;
- }
- if ( ! Character.isDigit(className.charAt(dollar + 1))) {
- return false;
- }
- int len = className.length();
- for (int i = dollar + 2; i < len; i++) {
- if (Character.isJavaIdentifierStart(className.charAt(i))) {
- return true;
- }
- }
- // all the characters past the $ are digits (anonymous)
- return false;
- }
-
- /**
- * Return whether the specified class is an "anonymous" class,
- * as opposed to a "top-level", "member", or "local" class,
- * using the standard jdk naming conventions (i.e. the class
- * name ends with '$nnn' where all the characters past the
- * last '$' are numeric digits: "TopLevelClass$1").
- * Class#isAnonymous()
- */
- public static boolean classNamedIsAnonymous(String className) {
- if (classNamedIsArray(className)) {
- return false;
- }
- int dollar = className.indexOf(NESTED_CLASS_NAME_SEPARATOR);
- if (dollar == -1) {
- return false;
- }
- int start = dollar + 1;
- for (int i = className.length(); i-- > start; ) {
- if ( ! Character.isDigit(className.charAt(i))) {
- return false;
- }
- }
- // all the characters past the $ are digits
- return true;
- }
-
- /**
- * Return the "array depth" of the specified class.
- * The depth is the number of dimensions for an array type.
- * Non-array types have a depth of zero.
- * Class#getArrayDepth()
- */
- public static int arrayDepthFor(Class<?> javaClass) {
- int depth = 0;
- while (javaClass.isArray()) {
- depth++;
- javaClass = javaClass.getComponentType();
- }
- return depth;
- }
-
- /**
- * Return the "array depth" of the specified object.
- * The depth is the number of dimensions for an array.
- * Non-arrays have a depth of zero.
- */
- public static int arrayDepthForObject(Object object) {
- return arrayDepthFor(object.getClass());
- }
-
- /**
- * Return the "array depth" of the specified class.
- * The depth is the number of dimensions for an array type.
- * Non-array types have a depth of zero.
- * @see java.lang.Class#getName()
- * Class#getArrayDepth()
- */
- public static int arrayDepthForClassNamed(String className) {
- int depth = 0;
- while (className.charAt(depth) == ARRAY_INDICATOR) {
- depth++;
- }
- return depth;
- }
-
- /**
- * Return whether the specified class is an array type.
- * @see java.lang.Class#getName()
- */
- public static boolean classNamedIsArray(String className) {
- return className.charAt(0) == ARRAY_INDICATOR;
- }
-
- /**
- * Return the "element type" of the specified class.
- * The element type is the base type held by an array type.
- * A non-array type simply returns itself.
- * Class#getElementType()
- */
- public static Class<?> elementTypeFor(Class<?> javaClass) {
- while (javaClass.isArray()) {
- javaClass = javaClass.getComponentType();
- }
- return javaClass;
- }
-
- /**
- * Return the "element type" of the specified object.
- * The element type is the base type held by an array.
- * A non-array simply returns its class.
- */
- public static Class<?> elementTypeForObject(Object object) {
- return elementTypeFor(object.getClass());
- }
-
- /**
- * Return the "element type" of the specified class.
- * The element type is the base type held by an array type.
- * Non-array types simply return themselves.
- * Class#getElementType()
- */
- public static String elementTypeNameFor(Class<?> javaClass) {
- return elementTypeFor(javaClass).getName();
- }
-
- /**
- * Return the "element type" of the specified class.
- * The element type is the base type held by an array type.
- * Non-array types simply return themselves.
- * @see java.lang.Class#getName()
- * Class#getElementType()
- */
- public static String elementTypeNameForClassNamed(String className) {
- int depth = arrayDepthForClassNamed(className);
- if (depth == 0) {
- // the name is in the form: "java.lang.Object" or "int"
- return className;
- }
- int last = className.length() - 1;
- if (className.charAt(depth) == REFERENCE_CLASS_CODE) {
- // the name is in the form: "[[[Ljava.lang.Object;"
- return className.substring(depth + 1, last); // drop the trailing ';'
- }
- // the name is in the form: "[[[I"
- return classNameForCode(className.charAt(last));
- }
-
- /**
- * Return whether the specified class is a "reference"
- * class (i.e. neither 'void' nor one of the primitive variable classes,
- * ['boolean', 'int', 'float', etc.]).
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classNamedIsReference(String className) {
- return ! classNamedIsPrimitive(className);
- }
-
- /**
- * Return whether the specified class is a primitive
- * class (i.e. 'void' or one of the primitive variable classes,
- * ['boolean', 'int', 'float', etc.]).
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classNamedIsPrimitive(String className) {
- if (classNamedIsArray(className) || (className.length() > maxPrimitiveClassNameLength())) {
- return false; // performance tweak
- }
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].javaClass.getName().equals(className)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified class is a "variable" primitive
- * class (i.e. 'boolean', 'int', 'float', etc., but not 'void').
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classNamedIsVariablePrimitive(String className) {
- return classNamedIsPrimitive(className)
- && ( ! className.equals(VOID_CLASS_NAME));
- }
-
- /**
- * Return whether the specified class is a primitive wrapper
- * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes,
- * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]).
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classNamedIsPrimitiveWrapperClass(String className) {
- if (classNamedIsArray(className) || (className.length() > maxPrimitiveWrapperClassNameLength())) {
- return false; // performance tweak
- }
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].wrapperClass.getName().equals(className)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified class is a "variable" primitive
- * class (i.e. 'boolean', 'int', 'float', etc., but not 'void').
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classNamedIsVariablePrimitiveWrapperClass(String className) {
- return classNamedIsPrimitiveWrapperClass(className)
- && ( ! className.equals(VOID_WRAPPER_CLASS_NAME));
- }
-
- /**
- * Return whether the specified class is a primitive wrapper
- * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes,
- * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]).
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classIsPrimitiveWrapperClass(Class<?> javaClass) {
- if (javaClass.isArray() || (javaClass.getName().length() > maxPrimitiveWrapperClassNameLength())) {
- return false; // performance tweak
- }
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].wrapperClass == javaClass) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified class is a "variable" primitive
- * class (i.e. 'boolean', 'int', 'float', etc., but not 'void').
- * NB: void.class.isPrimitive() == true
- */
- public static boolean classIsVariablePrimitiveWrapperClass(Class<?> javaClass) {
- return classIsPrimitiveWrapperClass(javaClass)
- && (javaClass != java.lang.Void.class);
- }
-
- /**
- * Return the class name for the specified class code.
- * @see java.lang.Class#getName()
- */
- public static String classNameForCode(char classCode) {
- return classForCode(classCode).getName();
- }
-
- /**
- * Return the class name for the specified class code.
- * @see java.lang.Class#getName()
- */
- public static String classNameForCode(int classCode) {
- return classNameForCode((char) classCode);
- }
-
- /**
- * Return the class for the specified class code.
- * @see java.lang.Class#getName()
- */
- public static Class<?> classForCode(char classCode) {
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].code == classCode) {
- return codes[i].javaClass;
- }
- }
- throw new IllegalArgumentException(String.valueOf(classCode));
- }
-
- /**
- * Return the class for the specified class code.
- * @see java.lang.Class#getName()
- */
- public static Class<?> classForCode(int classCode) {
- return classForCode((char) classCode);
- }
-
- /**
- * Return the class code for the specified class.
- * @see java.lang.Class#getName()
- */
- public static char codeForClass(Class<?> javaClass) {
- if (( ! javaClass.isArray()) && (javaClass.getName().length() <= maxPrimitiveClassNameLength())) {
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].javaClass == javaClass) {
- return codes[i].code;
- }
- }
- }
- throw new IllegalArgumentException(javaClass.getName());
- }
-
- /**
- * Return the class code for the specified class.
- * @see java.lang.Class#getName()
- */
- public static char codeForClassNamed(String className) {
- if (( ! classNamedIsArray(className)) && (className.length() <= maxPrimitiveClassNameLength())) {
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].javaClass.getName().equals(className)) {
- return codes[i].code;
- }
- }
- }
- throw new IllegalArgumentException(className);
- }
-
- /**
- * Return the class for the specified "type declaration".
- */
- public static Class<?> classForTypeDeclaration(String typeDeclaration) throws ClassNotFoundException {
- return classForTypeDeclaration(typeDeclaration, null);
- }
-
- /**
- * Return the class for the specified "type declaration",
- * using the specified class loader.
- */
- public static Class<?> classForTypeDeclaration(String typeDeclaration, ClassLoader classLoader) throws ClassNotFoundException {
- TypeDeclaration td = typeDeclaration(typeDeclaration);
- return classForTypeDeclaration(td.elementTypeName, td.arrayDepth, classLoader);
- }
-
- private static TypeDeclaration typeDeclaration(String typeDeclaration) {
- typeDeclaration = StringTools.removeAllWhitespace(typeDeclaration);
- int arrayDepth = arrayDepthForTypeDeclaration_(typeDeclaration);
- String elementTypeName = typeDeclaration.substring(0, typeDeclaration.length() - (arrayDepth * 2));
- return new TypeDeclaration(elementTypeName, arrayDepth);
- }
-
- /**
- * Return the class for the specified "type declaration".
- */
- public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth) throws ClassNotFoundException {
- return classForTypeDeclaration(elementTypeName, arrayDepth, null);
- }
-
- /**
- * Return the class for the specified "type declaration",
- * using the specified class loader.
- */
- // see the "Evaluation" of jdk bug 6446627 for a discussion of loading classes
- public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth, ClassLoader classLoader) throws ClassNotFoundException {
- // primitives cannot be loaded via Class#forName(),
- // so check for a primitive class name first
- Primitive pcc = null;
- if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].javaClass.getName().equals(elementTypeName)) {
- pcc = codes[i];
- break;
- }
- }
- }
-
- // non-array
- if (arrayDepth == 0) {
- return (pcc == null) ? Class.forName(elementTypeName, false, classLoader) : pcc.javaClass;
- }
-
- // array
- StringBuilder sb = new StringBuilder(100);
- for (int i = arrayDepth; i-- > 0; ) {
- sb.append(ARRAY_INDICATOR);
- }
- if (pcc == null) {
- sb.append(REFERENCE_CLASS_CODE);
- sb.append(elementTypeName);
- sb.append(REFERENCE_CLASS_NAME_DELIMITER);
- } else {
- sb.append(pcc.code);
- }
- return Class.forName(sb.toString(), false, classLoader);
- }
-
- /**
- * Return the class name for the specified "type declaration"; e.g.
- * "int[]" -> "[I"
- * @see java.lang.Class#getName()
- */
- public static String classNameForTypeDeclaration(String typeDeclaration) {
- TypeDeclaration td = typeDeclaration(typeDeclaration);
- return classNameForTypeDeclaration(td.elementTypeName, td.arrayDepth);
- }
-
- /**
- * Return the array depth for the specified "type declaration"; e.g.
- * "int[]" -> 1
- */
- public static int arrayDepthForTypeDeclaration(String typeDeclaration) {
- return arrayDepthForTypeDeclaration_(StringTools.removeAllWhitespace(typeDeclaration));
- }
-
- /*
- * Assume no whitespace in the type declaration.
- */
- private static int arrayDepthForTypeDeclaration_(String typeDeclaration) {
- int last = typeDeclaration.length() - 1;
- int depth = 0;
- int close = last;
- while (typeDeclaration.charAt(close) == TYPE_DECLARATION_ARRAY_CLOSE) {
- if (typeDeclaration.charAt(close - 1) == TYPE_DECLARATION_ARRAY_OPEN) {
- depth++;
- } else {
- throw new IllegalArgumentException("invalid type declaration: " + typeDeclaration); //$NON-NLS-1$
- }
- close = last - (depth * 2);
- }
- return depth;
- }
-
- /**
- * Return the class name for the specified "type declaration".
- * @see java.lang.Class#getName()
- */
- public static String classNameForTypeDeclaration(String elementTypeName, int arrayDepth) {
- // non-array
- if (arrayDepth == 0) {
- return elementTypeName;
- }
-
- if (elementTypeName.equals(VOID_CLASS_NAME)) {
- throw new IllegalArgumentException('\'' + VOID_CLASS_NAME + "' must have an array depth of zero: " + arrayDepth + '.'); //$NON-NLS-1$
- }
- // array
- StringBuilder sb = new StringBuilder(100);
- for (int i = arrayDepth; i-- > 0; ) {
- sb.append(ARRAY_INDICATOR);
- }
-
- // look for a primitive first
- Primitive pcc = null;
- if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- if (codes[i].javaClass.getName().equals(elementTypeName)) {
- pcc = codes[i];
- break;
- }
- }
- }
-
- if (pcc == null) {
- sb.append(REFERENCE_CLASS_CODE);
- sb.append(elementTypeName);
- sb.append(REFERENCE_CLASS_NAME_DELIMITER);
- } else {
- sb.append(pcc.code);
- }
-
- return sb.toString();
- }
-
- private static int maxPrimitiveClassNameLength() {
- if (MAX_PRIMITIVE_CLASS_NAME_LENGTH == -1) {
- MAX_PRIMITIVE_CLASS_NAME_LENGTH = calculateMaxPrimitiveClassNameLength();
- }
- return MAX_PRIMITIVE_CLASS_NAME_LENGTH;
- }
-
- private static int calculateMaxPrimitiveClassNameLength() {
- int max = -1;
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- int len = codes[i].javaClass.getName().length();
- if (len > max) {
- max = len;
- }
- }
- return max;
- }
-
- private static int maxPrimitiveWrapperClassNameLength() {
- if (MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH == -1) {
- MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = calculateMaxPrimitiveWrapperClassNameLength();
- }
- return MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH;
- }
-
- private static int calculateMaxPrimitiveWrapperClassNameLength() {
- int max = -1;
- Primitive[] codes = primitives();
- for (int i = codes.length; i-- > 0; ) {
- int len = codes[i].wrapperClass.getName().length();
- if (len > max) {
- max = len;
- }
- }
- return max;
- }
-
- private static Primitive[] primitives() {
- if (PRIMITIVES == null) {
- PRIMITIVES = buildPrimitives();
- }
- return PRIMITIVES;
- }
-
- /**
- * NB: void.class.isPrimitive() == true
- */
- private static Primitive[] buildPrimitives() {
- Primitive[] result = new Primitive[9];
- result[0] = new Primitive(BYTE_CODE, java.lang.Byte.class);
- result[1] = new Primitive(CHAR_CODE, java.lang.Character.class);
- result[2] = new Primitive(DOUBLE_CODE, java.lang.Double.class);
- result[3] = new Primitive(FLOAT_CODE, java.lang.Float.class);
- result[4] = new Primitive(INT_CODE, java.lang.Integer.class);
- result[5] = new Primitive(LONG_CODE, java.lang.Long.class);
- result[6] = new Primitive(SHORT_CODE, java.lang.Short.class);
- result[7] = new Primitive(BOOLEAN_CODE, java.lang.Boolean.class);
- result[8] = new Primitive(VOID_CODE, java.lang.Void.class);
- return result;
- }
-
- /**
- * Suppress default constructor, ensuring non-instantiability.
- */
- private ClassTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-
- // ********** member classes **********
-
- private static class Primitive {
- final char code;
- final Class<?> javaClass;
- final Class<?> wrapperClass;
- private static final String WRAPPER_CLASS_TYPE_FIELD_NAME = "TYPE"; //$NON-NLS-1$
- // e.g. java.lang.Boolean.TYPE => boolean.class
- Primitive(char code, Class<?> wrapperClass) {
- this.code = code;
- this.wrapperClass = wrapperClass;
- this.javaClass = (Class<?>) staticFieldValue(wrapperClass, WRAPPER_CLASS_TYPE_FIELD_NAME);
- }
- }
-
- private static class TypeDeclaration {
- final String elementTypeName;
- final int arrayDepth;
- TypeDeclaration(String elementTypeName, int arrayDepth) {
- this.elementTypeName = elementTypeName;
- this.arrayDepth = arrayDepth;
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java
deleted file mode 100644
index 1d21184745..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Classpath.java
+++ /dev/null
@@ -1,911 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.eclipse.jpt.utility.Filter;
-import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
-import org.eclipse.jpt.utility.internal.iterators.CompositeIterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.internal.iterators.FilteringIterator;
-import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
-
-/**
- * TODO
- */
-public class Classpath
- implements Serializable
-{
- /** The entries in the classpath */
- private final Entry[] entries;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** static methods **********
-
- // ***** factory methods for "standard" classpaths *****
-
- /**
- * Return the Java "boot" classpath. This includes rt.jar.
- */
- public static Classpath bootClasspath() {
- return new Classpath(System.getProperty("sun.boot.class.path")); //$NON-NLS-1$
- }
-
- /**
- * Return a "virtual classpath" that contains all the jars
- * that would be used by the Java Extension Mechanism.
- */
- public static Classpath javaExtensionClasspath() {
- File[] dirs = javaExtensionDirectories();
- List<String> jarFileNames = new ArrayList<String>();
- for (File dir : dirs) {
- if (dir.isDirectory()) {
- addJarFileNamesTo(dir, jarFileNames);
- }
- }
- return new Classpath(jarFileNames);
- }
-
- /**
- * Return the Java "system" classpath.
- */
- public static Classpath javaClasspath() {
- return new Classpath(System.getProperty("java.class.path")); //$NON-NLS-1$
- }
-
- /**
- * Return the unretouched "complete" classpath.
- * This includes the boot classpath, the Java Extension
- * Mechanism classpath, and the normal "system" classpath.
- */
- public static Classpath completeClasspath() {
- return new Classpath(new Classpath[] {
- bootClasspath(),
- javaExtensionClasspath(),
- javaClasspath()
- });
- }
-
- /**
- * Return a classpath that contains the location of the specified class.
- */
- public static Classpath classpathFor(Class<?> javaClass) {
- return new Classpath(locationFor(javaClass));
- }
-
-
- // ***** file => class *****
-
- /**
- * Convert a relative file name to a class name; this will work for
- * any file that has a single extension beyond the base
- * class name.
- * e.g. "java/lang/String.class" is converted to "java.lang.String"
- * e.g. "java/lang/String.java" is converted to "java.lang.String"
- */
- public static String convertToClassName(String classFileName) {
- String className = FileTools.stripExtension(classFileName);
- // do this for archive entry names
- className = className.replace('/', '.');
- // do this for O/S-specific file names
- if (File.separatorChar != '/') {
- className = className.replace(File.separatorChar, '.');
- }
- return className;
- }
-
- /**
- * Convert a file to a class name;
- * e.g. File(java/lang/String.class) is converted to "java.lang.String"
- */
- public static String convertToClassName(File classFile) {
- return convertToClassName(classFile.getPath());
- }
-
- /**
- * Convert a relative file name to a class;
- * e.g. "java/lang/String.class" is converted to java.lang.String.class
- */
- public static Class<?> convertToClass(String classFileName) throws ClassNotFoundException {
- return Class.forName(convertToClassName(classFileName));
- }
-
- /**
- * Convert a relative file to a class;
- * e.g. File(java/lang/String.class) is converted to java.lang.String.class
- */
- public static Class<?> convertToClass(File classFile) throws ClassNotFoundException {
- return convertToClass(classFile.getPath());
- }
-
-
- // ***** class => JAR entry *****
-
- /**
- * Convert a class name to an archive entry name base;
- * e.g. "java.lang.String" is converted to "java/lang/String"
- */
- public static String convertToArchiveEntryNameBase(String className) {
- return className.replace('.', '/');
- }
-
- /**
- * Convert a class to an archive entry name base;
- * e.g. java.lang.String.class is converted to "java/lang/String"
- */
- public static String convertToArchiveEntryNameBase(Class<?> javaClass) {
- return convertToArchiveEntryNameBase(javaClass.getName());
- }
-
- /**
- * Convert a class name to an archive class file entry name;
- * e.g. "java.lang.String" is converted to "java/lang/String.class"
- */
- public static String convertToArchiveClassFileEntryName(String className) {
- return convertToArchiveEntryNameBase(className) + ".class"; //$NON-NLS-1$
- }
-
- /**
- * Convert a class to an archive class file entry name;
- * e.g. java.lang.String.class is converted to "java/lang/String.class"
- */
- public static String convertToArchiveClassFileEntryName(Class<?> javaClass) {
- return convertToArchiveClassFileEntryName(javaClass.getName());
- }
-
-
- // ***** class => file (.class or .java) *****
-
- /**
- * Convert a class name to a file name base for the current O/S;
- * e.g. "java.lang.String" is converted to "java/lang/String" on Unix
- * and "java\\lang\\String" on Windows
- */
- public static String convertToFileNameBase(String className) {
- return className.replace('.', File.separatorChar);
- }
-
- /**
- * Convert a class to a file name base for the current O/S;
- * e.g. java.lang.String.class is converted to "java/lang/String" on Unix
- * and "java\\lang\\String" on Windows
- */
- public static String convertToFileNameBase(Class<?> javaClass) {
- return convertToFileNameBase(javaClass.getName());
- }
-
- /**
- * Convert a class name to a class file name for the current O/S;
- * e.g. "java.lang.String" is converted to "java/lang/String.class" on Unix
- * and "java\\lang\\String.class" on Windows
- */
- public static String convertToClassFileName(String className) {
- return convertToFileNameBase(className) + ".class"; //$NON-NLS-1$
- }
-
- /**
- * Convert a class to a class file name for the current O/S;
- * e.g. java.lang.String.class is converted to "java/lang/String.class" on Unix
- * and "java\\lang\\String.class" on Windows
- */
- public static String convertToClassFileName(Class<?> javaClass) {
- return convertToClassFileName(javaClass.getName());
- }
-
- /**
- * Convert a class name to a class file for the current O/S;
- * e.g. "java.lang.String" is converted to File(java/lang/String.class)
- */
- public static File convertToClassFile(String className) {
- return new File(convertToClassFileName(className));
- }
-
- /**
- * Convert a class to a class file for the current O/S;
- * e.g. java.lang.String.class is converted to File(java/lang/String.class)
- */
- public static File convertToClassFile(Class<?> javaClass) {
- return convertToClassFile(javaClass.getName());
- }
-
- /**
- * Convert a class name to a java file name for the current O/S;
- * e.g. "java.lang.String" is converted to "java/lang/String.java" on Unix
- * and "java\\lang\\String.java" on Windows
- */
- public static String convertToJavaFileName(String className) {
- return convertToFileNameBase(className) + ".java"; //$NON-NLS-1$
- }
-
- /**
- * Convert a class to a java file name for the current O/S;
- * e.g. java.lang.String.class is converted to "java/lang/String.java" on Unix
- * and "java\\lang\\String.java" on Windows
- */
- public static String convertToJavaFileName(Class<?> javaClass) {
- return convertToJavaFileName(javaClass.getName());
- }
-
- /**
- * Convert a class name to a java file for the current O/S;
- * e.g. "java.lang.String" is converted to File(java/lang/String.java)
- */
- public static File convertToJavaFile(String className) {
- return new File(convertToJavaFileName(className));
- }
-
- /**
- * Convert a class to a java file for the current O/S;
- * e.g. java.lang.String.class is converted to File(java/lang/String.java)
- */
- public static File convertToJavaFile(Class<?> javaClass) {
- return convertToJavaFile(javaClass.getName());
- }
-
-
- // ***** class => resource *****
-
- /**
- * Convert a class to a resource name;
- * e.g. java.lang.String.class is converted to "/java/lang/String.class".
- */
- public static String convertToResourceName(Class<?> javaClass) {
- return '/' + convertToArchiveClassFileEntryName(javaClass);
- }
-
- /**
- * Convert a class to a resource;
- * e.g. java.lang.String.class is converted to
- * URL(jar:file:/C:/jdk/1.4.2_04/jre/lib/rt.jar!/java/lang/String.class).
- */
- public static URL convertToResource(Class<?> javaClass) {
- return javaClass.getResource(convertToResourceName(javaClass));
- }
-
-
- // ***** utilities *****
-
- /**
- * Return whether the specified file is an archive file;
- * i.e. its name ends with ".zip" or ".jar"
- */
- public static boolean fileNameIsArchive(String fileName) {
- String ext = FileTools.extension(fileName).toLowerCase();
- return ext.equals(".jar") || ext.equals(".zip"); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- /**
- * Return whether the specified file is an archive file;
- * i.e. its name ends with ".zip" or ".jar"
- */
- public static boolean fileIsArchive(File file) {
- return fileNameIsArchive(file.getName());
- }
-
- /**
- * Return what should be the fully-qualified file name
- * for the JRE runtime JAR;
- * e.g. "C:\jdk1.4.2_04\jre\lib\rt.jar".
- */
- public static String rtJarName() {
- return locationFor(java.lang.Object.class);
- }
-
- /**
- * Return the location from where the specified class was loaded.
- */
- public static String locationFor(Class<?> javaClass) {
- URL url = convertToResource(javaClass);
- String path;
- try {
- path = FileTools.buildFile(url).getPath();
- } catch (URISyntaxException ex) {
- throw new RuntimeException(ex);
- }
- String protocol = url.getProtocol().toLowerCase();
- if (protocol.equals("jar")) { //$NON-NLS-1$
- // if the class is in a JAR, the URL will look something like this:
- // jar:file:/C:/jdk/1.4.2_04/jre/lib/rt.jar!/java/lang/String.class
- return path.substring(0, path.indexOf('!'));
- } else if (protocol.equals("file")) { //$NON-NLS-1$
- // if the class is in a directory, the URL will look something like this:
- // file:/C:/dev/main/mwdev/class/org/eclipse/dali/utility/Classpath.class
- return path.substring(0, path.length() - convertToClassFileName(javaClass).length() - 1);
- } else if (protocol.equals("bundleresource")) { //$NON-NLS-1$
- // if the class is in a bundle resource (Eclipse?), the URL will look something like this:
- // bundleresource://43/org/eclipse/dali/utility/Classpath.class
- return path.substring(0, path.length() - convertToClassFileName(javaClass).length() - 1);
- }
-
- throw new IllegalStateException(url.toString());
- }
-
- /**
- * Return the directories used by the Java Extension Mechanism.
- */
- public static File[] javaExtensionDirectories() {
- return convertToFiles(javaExtensionDirectoryNames());
- }
-
- /**
- * Return the directory names used by the Java Extension Mechanism.
- */
- public static String[] javaExtensionDirectoryNames() {
- return System.getProperty("java.ext.dirs").split(File.pathSeparator); //$NON-NLS-1$
- }
-
-
- // ***** internal *****
-
- private static File[] convertToFiles(String[] fileNames) {
- File[] files = new File[fileNames.length];
- for (int i = fileNames.length; i-- > 0; ) {
- files[i] = new File(fileNames[i]);
- }
- return files;
- }
-
- private static void addJarFileNamesTo(File dir, List<String> jarFileNames) {
- File[] jarFiles = jarFilesIn(dir);
- for (File jarFile : jarFiles) {
- jarFileNames.add(FileTools.canonicalFile(jarFile).getPath());
- }
- }
-
- private static File[] jarFilesIn(File directory) {
- return directory.listFiles(jarFileFilter());
- }
-
- private static FileFilter jarFileFilter() {
- return new FileFilter() {
- public boolean accept(File file) {
- return FileTools.extension(file.getName()).toLowerCase().equals(".jar"); //$NON-NLS-1$
- }
- };
- }
-
-
- // ********** constructors **********
-
- /**
- * Construct a classpath with the specified entries.
- */
- private Classpath(Entry[] entries) {
- super();
- this.entries = entries;
- }
-
- /**
- * Construct a classpath with the specified entries.
- */
- public Classpath(String[] fileNames) {
- this(buildEntries(fileNames));
- }
-
- /**
- * Skip empty file names because they will end up expanding to the current
- * working directory, which is not what we want. Empty file names actually
- * occur with some frequency; such as when the classpath has been built up
- * dynamically with too many separators. For example:
- * "C:\dev\foo.jar;;C:\dev\bar.jar"
- * will be parsed into three file names:
- * { "C:\dev\foo.jar", "", "C:\dev\bar.jar" }
- */
- private static Entry[] buildEntries(String[] fileNames) {
- List<Entry> entries = new ArrayList<Entry>();
- for (String fileName : fileNames) {
- if ((fileName != null) && (fileName.length() != 0)) {
- entries.add(new Entry(fileName));
- }
- }
- return entries.toArray(new Entry[entries.size()]);
- }
-
- /**
- * Construct a classpath with the specified path.
- */
- public Classpath(String path) {
- this(path.split(File.pathSeparator));
- }
-
- /**
- * Construct a classpath with the specified entries.
- */
- public Classpath(List<String> fileNames) {
- this(fileNames.toArray(new String[fileNames.size()]));
- }
-
- /**
- * Consolidate the specified classpaths into a single classpath.
- */
- public Classpath(Classpath[] classpaths) {
- this(consolidateEntries(classpaths));
- }
-
- private static Entry[] consolidateEntries(Classpath[] classpaths) {
- List<Entry> entries = new ArrayList<Entry>();
- for (Classpath classpath : classpaths) {
- CollectionTools.addAll(entries, classpath.entries());
- }
- return entries.toArray(new Entry[entries.size()]);
- }
-
-
- // ********** public API **********
-
- /**
- * Return the classpath's entries.
- */
- public Entry[] entries() {
- return this.entries;
- }
-
- /**
- * Return the classpath's path.
- */
- public String path() {
- Entry[] localEntries = this.entries;
- int max = localEntries.length - 1;
- if (max == -1) {
- return ""; //$NON-NLS-1$
- }
- StringBuilder sb = new StringBuilder(2000);
- // stop one short of the end of the array
- for (int i = 0; i < max; i++) {
- sb.append(localEntries[i].fileName());
- sb.append(File.pathSeparatorChar);
- }
- sb.append(localEntries[max].fileName());
- return sb.toString();
- }
-
- /**
- * Search the classpath for the specified (unqualified) file
- * and return its entry. Return null if an entry is not found.
- * For example, you could use this method to find the entry
- * for "rt.jar" or "toplink.jar".
- */
- public Entry entryForFileNamed(String shortFileName) {
- Entry[] localEntries = this.entries;
- for (Entry entry : localEntries) {
- if (entry.file().getName().equals(shortFileName)) {
- return entry;
- }
- }
- return null;
- }
-
- /**
- * Return the first entry file in the classpath
- * that contains the specified class.
- * Return null if an entry is not found.
- */
- public Entry entryForClassNamed(String className) {
- String relativeClassFileName = convertToClassFileName(className);
- String archiveEntryName = convertToArchiveClassFileEntryName(className);
- Entry[] localEntries = this.entries;
- for (Entry entry : localEntries) {
- if (entry.contains(relativeClassFileName, archiveEntryName)) {
- return entry;
- }
- }
- return null;
- }
-
- /**
- * Return the names of all the classes discovered on the classpath,
- * with duplicates removed.
- */
- public String[] classNames() {
- return this.classNames(Filter.Null.<String>instance());
- }
-
- /**
- * Return the names of all the classes discovered on the classpath
- * and accepted by the specified filter, with duplicates removed.
- */
- public String[] classNames(Filter<String> filter) {
- Collection<String> classNames = new HashSet<String>(10000);
- this.addClassNamesTo(classNames, filter);
- return classNames.toArray(new String[classNames.size()]);
- }
-
- /**
- * Add the names of all the classes discovered on the classpath
- * to the specified collection.
- */
- public void addClassNamesTo(Collection<String> classNames) {
- this.addClassNamesTo(classNames, Filter.Null.<String>instance());
- }
-
- /**
- * Add the names of all the classes discovered on the classpath
- * and accepted by the specified filter to the specified collection.
- */
- public void addClassNamesTo(Collection<String> classNames, Filter<String> filter) {
- Entry[] localEntries = this.entries;
- for (Entry entry : localEntries) {
- entry.addClassNamesTo(classNames, filter);
- }
- }
-
- /**
- * Return the names of all the classes discovered on the classpath.
- * Just a bit more performant than #classNames().
- */
- public Iterator<String> classNamesStream() {
- return this.classNamesStream(Filter.Null.<String>instance());
- }
-
- /**
- * Return the names of all the classes discovered on the classpath
- * that are accepted by the specified filter.
- * Just a bit more performant than #classNames(Filter).
- */
- public Iterator<String> classNamesStream(Filter<String> filter) {
- return new CompositeIterator<String>(this.entryClassNamesStreams(filter));
- }
-
- private Iterator<Iterator<String>> entryClassNamesStreams(final Filter<String> filter) {
- return new TransformationIterator<Entry, Iterator<String>>(new ArrayIterator<Entry>(this.entries)) {
- @Override
- protected Iterator<String> transform(Entry entry) {
- return entry.classNamesStream(filter);
- }
- };
- }
-
- /**
- * Return a "compressed" version of the classpath with its
- * duplicate entries eliminated.
- */
- public Classpath compressed() {
- return new Classpath(CollectionTools.removeDuplicateElements(this.entries));
- }
-
- /**
- * Convert the classpath to an array of URLs
- * (that can be used to instantiate a URLClassLoader).
- */
- public URL[] urls() {
- Entry[] localEntries = this.entries;
- int len = localEntries.length;
- URL[] urls = new URL[len];
- for (int i = 0; i < len; i++) {
- urls[i] = localEntries[i].url();
- }
- return urls;
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.path());
- }
-
-
- // ********** inner class **********
-
- /**
- * TODO
- */
- public static class Entry implements Serializable {
- private final String fileName;
- private final File file;
- private final File canonicalFile;
-
- private static final long serialVersionUID = 1L;
-
- Entry(String fileName) {
- super();
- if ((fileName == null) || (fileName.length() == 0)) {
- throw new IllegalArgumentException("'fileName' must be non-empty"); //$NON-NLS-1$
- }
- this.fileName = fileName;
- this.file = new File(fileName);
- this.canonicalFile = FileTools.canonicalFile(this.file);
- }
-
- public String fileName() {
- return this.fileName;
- }
-
- public File file() {
- return this.file;
- }
-
- public File canonicalFile() {
- return this.canonicalFile;
- }
-
- public String canonicalFileName() {
- return this.canonicalFile.getAbsolutePath();
- }
-
- @Override
- public boolean equals(Object o) {
- if ( ! (o instanceof Entry)) {
- return false;
- }
- return ((Entry) o).canonicalFile.equals(this.canonicalFile);
- }
-
- @Override
- public int hashCode() {
- return this.canonicalFile.hashCode();
- }
-
- /**
- * Return the entry's "canonical" URL.
- */
- public URL url() {
- try {
- return this.canonicalFile.toURL();
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- /**
- * Return whether the entry contains the specified class.
- */
- public boolean contains(Class<?> javaClass) {
- return this.contains(javaClass.getName());
- }
-
- /**
- * Return whether the entry contains the specified class.
- */
- public boolean contains(String className) {
- return this.contains(convertToClassFileName(className), convertToArchiveClassFileEntryName(className));
- }
-
- /**
- * Return whether the entry contains either the specified relative
- * class file or the specified archive entry.
- * Not the prettiest signature, but it's internal....
- */
- boolean contains(String relativeClassFileName, String archiveEntryName) {
- if ( ! this.canonicalFile.exists()) {
- return false;
- }
- if (this.canonicalFile.isDirectory() && (new File(this.canonicalFile, relativeClassFileName)).exists()) {
- return true;
- }
- return (fileIsArchive(this.canonicalFile) && this.archiveContainsEntry(archiveEntryName));
- }
-
- /**
- * Return whether the entry's archive contains the specified entry.
- */
- private boolean archiveContainsEntry(String zipEntryName) {
- ZipFile zipFile = null;
- ZipEntry zipEntry = null;
- try {
- zipFile = new ZipFile(this.canonicalFile);
- zipEntry = zipFile.getEntry(zipEntryName);
- } catch (IOException ex) {
- // something is wrong, leave the entry null
- } finally {
- try {
- if (zipFile != null) {
- zipFile.close();
- }
- } catch (IOException ex) {
- zipEntry = null; // something is wrong, clear out the entry
- }
- }
- return zipEntry != null;
- }
-
- /**
- * Return the names of all the classes discovered in the entry.
- */
- public String[] classNames() {
- return this.classNames(Filter.Null.<String>instance());
- }
-
- /**
- * Return the names of all the classes discovered in the entry
- * and accepted by the specified filter.
- */
- public String[] classNames(Filter<String> filter) {
- Collection<String> classNames = new ArrayList<String>(2000);
- this.addClassNamesTo(classNames, filter);
- return classNames.toArray(new String[classNames.size()]);
- }
-
- /**
- * Add the names of all the classes discovered in the entry
- * to the specified collection.
- */
- public void addClassNamesTo(Collection<String> classNames) {
- this.addClassNamesTo(classNames, Filter.Null.<String>instance());
- }
-
- /**
- * Add the names of all the classes discovered in the entry
- * and accepted by the specified filter to the specified collection.
- */
- public void addClassNamesTo(Collection<String> classNames, Filter<String> filter) {
- if (this.canonicalFile.exists()) {
- if (this.canonicalFile.isDirectory()) {
- this.addClassNamesForDirectoryTo(classNames, filter);
- } else if (fileIsArchive(this.canonicalFile)) {
- this.addClassNamesForArchiveTo(classNames, filter);
- }
- }
- }
-
- /**
- * Add the names of all the classes discovered
- * under the entry's directory and accepted by
- * the specified filter to the specified collection.
- */
- private void addClassNamesForDirectoryTo(Collection<String> classNames, Filter<String> filter) {
- int start = this.canonicalFile.getAbsolutePath().length() + 1;
- for (Iterator<File> stream = this.classFilesForDirectory(); stream.hasNext(); ) {
- String className = convertToClassName(stream.next().getAbsolutePath().substring(start));
- if (filter.accept(className)) {
- classNames.add(className);
- }
- }
- }
-
- /**
- * Return an iterator on all the class files discovered
- * under the entry's directory.
- */
- private Iterator<File> classFilesForDirectory() {
- return new FilteringIterator<File, File>(FileTools.filesInTree(this.canonicalFile)) {
- @Override
- protected boolean accept(File next) {
- return Entry.this.fileNameMightBeForClassFile(next.getName());
- }
- };
- }
-
- /**
- * Add the names of all the classes discovered
- * in the entry's archive file and accepted by the
- * specified filter to the specified collection.
- */
- private void addClassNamesForArchiveTo(Collection<String> classNames, Filter<String> filter) {
- ZipFile zipFile = null;
- try {
- zipFile = new ZipFile(this.canonicalFile);
- } catch (IOException ex) {
- return;
- }
- for (Enumeration<? extends ZipEntry> stream = zipFile.entries(); stream.hasMoreElements(); ) {
- ZipEntry zipEntry = stream.nextElement();
- String zipEntryName = zipEntry.getName();
- if (this.fileNameMightBeForClassFile(zipEntryName)) {
- String className = convertToClassName(zipEntryName);
- if (filter.accept(className)) {
- classNames.add(className);
- }
- }
- }
- try {
- zipFile.close();
- } catch (IOException ex) {
- return;
- }
- }
-
- /**
- * Return whether the specified file might be a Java class file.
- * The file name must at least end with ".class" and contain no spaces.
- * (Neither class names nor package names may contain spaces.)
- * Whether it actually is a class file will need to be determined by
- * a class loader.
- */
- boolean fileNameMightBeForClassFile(String name) {
- return FileTools.extension(name).toLowerCase().equals(".class") //$NON-NLS-1$
- && (name.indexOf(' ') == -1);
- }
-
- /**
- * Return the names of all the classes discovered on the classpath.
- * Just a bit more performant than #classNames().
- */
- public Iterator<String> classNamesStream() {
- return this.classNamesStream(Filter.Null.<String>instance());
- }
-
- /**
- * Return the names of all the classes discovered on the classpath
- * that are accepted by the specified filter.
- * Just a bit more performant than #classNames(Filter).
- */
- public Iterator<String> classNamesStream(Filter<String> filter) {
- if (this.canonicalFile.exists()) {
- if (this.canonicalFile.isDirectory()) {
- return this.classNamesForDirectory(filter);
- }
- if (fileIsArchive(this.canonicalFile)) {
- return this.classNamesForArchive(filter);
- }
- }
- return EmptyIterator.instance();
- }
-
- /**
- * Return the names of all the classes discovered
- * under the entry's directory and accepted by
- * the specified filter.
- */
- private Iterator<String> classNamesForDirectory(Filter<String> filter) {
- return new FilteringIterator<String, String>(this.classNamesForDirectory(), filter);
- }
-
- /**
- * Transform the class files to class names.
- */
- private Iterator<String> classNamesForDirectory() {
- final int start = this.canonicalFile.getAbsolutePath().length() + 1;
- return new TransformationIterator<File, String>(this.classFilesForDirectory()) {
- @Override
- protected String transform(File f) {
- return convertToClassName(f.getAbsolutePath().substring(start));
- }
- };
- }
-
- /**
- * Return the names of all the classes discovered
- * in the entry's archive file and accepted by the
- * specified filter.
- */
- private Iterator<String> classNamesForArchive(Filter<String> filter) {
- // we can't simply wrap iterators here because we need to close the archive file...
- ZipFile zipFile = null;
- try {
- zipFile = new ZipFile(this.canonicalFile);
- } catch (IOException ex) {
- return EmptyIterator.instance();
- }
- Collection<String> classNames = new HashSet<String>(zipFile.size());
- for (Enumeration<? extends ZipEntry> stream = zipFile.entries(); stream.hasMoreElements(); ) {
- ZipEntry zipEntry = stream.nextElement();
- String zipEntryName = zipEntry.getName();
- if (this.fileNameMightBeForClassFile(zipEntryName)) {
- String className = convertToClassName(zipEntryName);
- if (filter.accept(className)) {
- classNames.add(className);
- }
- }
- }
- try {
- zipFile.close();
- } catch (IOException ex) {
- return EmptyIterator.instance();
- }
- return classNames.iterator();
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java
deleted file mode 100644
index a30650564a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CollectionTools.java
+++ /dev/null
@@ -1,3918 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Random;
-import java.util.RandomAccess;
-import java.util.TreeSet;
-import java.util.Vector;
-import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
-import org.eclipse.jpt.utility.internal.iterators.GenericIteratorWrapper;
-import org.eclipse.jpt.utility.internal.iterators.SingleElementIterator;
-
-public final class CollectionTools {
-
- @SuppressWarnings("unchecked")
- private static <E> E[] newArray(E[] array, int length) {
- return (E[]) Array.newInstance(array.getClass().getComponentType(), length);
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the specified object to be added.
- * java.util.Arrays#add(Object[] array, Object o)
- */
- public static <E> E[] add(E[] array, E value) {
- int len = array.length;
- E[] result = newArray(array, len + 1);
- if (len > 0) {
- System.arraycopy(array, 0, result, 0, len);
- }
- result[len] = value;
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified object added at the specified index.
- * java.util.Arrays#add(Object[] array, int index, Object o)
- */
- public static <E> E[] add(E[] array, int index, E value) {
- int len = array.length;
- E[] result = newArray(array, len + 1);
- if (index > 0) {
- System.arraycopy(array, 0, result, 0, index);
- }
- result[index] = value;
- if (len > index) {
- System.arraycopy(array, index, result, index + 1, len - index);
- }
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the specified value to be added.
- * java.util.Arrays#add(char[] array, char value)
- */
- public static char[] add(char[] array, char value) {
- int len = array.length;
- char[] result = new char[len + 1];
- if (len > 0) {
- System.arraycopy(array, 0, result, 0, len);
- }
- result[len] = value;
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified value added at the specified index.
- * java.util.Arrays#add(char[] array, int index, char value)
- */
- public static char[] add(char[] array, int index, char value) {
- int len = array.length;
- char[] result = new char[len + 1];
- if (index > 0) {
- System.arraycopy(array, 0, result, 0, index);
- }
- result[index] = value;
- if (len > index) {
- System.arraycopy(array, index, result, index + 1, len - index);
- }
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the specified value to be added.
- * java.util.Arrays#add(int[] array, int value)
- */
- public static int[] add(int[] array, int value) {
- int len = array.length;
- int[] result = new int[len + 1];
- if (len > 0) {
- System.arraycopy(array, 0, result, 0, len);
- }
- result[len] = value;
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified value added at the specified index.
- * java.util.Arrays#add(int[] array, int index, int value)
- */
- public static int[] add(int[] array, int index, int value) {
- int len = array.length;
- int[] result = new int[len + 1];
- if (index > 0) {
- System.arraycopy(array, 0, result, 0, index);
- }
- result[index] = value;
- if (len > index) {
- System.arraycopy(array, index, result, index + 1, len - index);
- }
- return result;
- }
-
- /**
- * Add all the elements returned by the specified iterable
- * to the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#addAll(java.lang.Iterable iterable)
- */
- public static <E> boolean addAll(Collection<? super E> collection, Iterable<? extends E> iterable) {
- return addAll(collection, iterable.iterator());
- }
-
- /**
- * Add all the elements returned by the specified iterable
- * to the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#addAll(java.lang.Iterable iterable)
- */
- public static <E> boolean addAll(Collection<? super E> collection, Iterable<? extends E> iterable, int size) {
- return addAll(collection, iterable.iterator(), size);
- }
-
- /**
- * Add all the elements returned by the specified iterator
- * to the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#addAll(java.util.Iterator iterator)
- */
- public static <E> boolean addAll(Collection<? super E> collection, Iterator<? extends E> iterator) {
- return (iterator.hasNext()) ? collection.addAll(list(iterator)) : false;
- }
-
- /**
- * Add all the elements returned by the specified iterator
- * to the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#addAll(java.util.Iterator iterator)
- */
- public static <E> boolean addAll(Collection<? super E> collection, Iterator<? extends E> iterator, int size) {
- return (iterator.hasNext()) ? collection.addAll(list(iterator, size)) : false;
- }
-
- /**
- * Add all the elements in the specified array
- * to the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#addAll(Object[] array)
- */
- public static <E> boolean addAll(Collection<? super E> collection, E[] array) {
- return (array.length == 0) ? false : collection.addAll(Arrays.asList(array));
- }
-
- /**
- * Add all the elements returned by the specified iterable
- * to the specified list at the specified index.
- * Return whether the list changed as a result.
- * java.util.List#addAll(java.lang.Iterable iterable)
- */
- public static <E> boolean addAll(List<? super E> list, int index, Iterable<E> iterable) {
- return addAll(list, index, iterable.iterator());
- }
-
- /**
- * Add all the elements returned by the specified iterable
- * to the specified list at the specified index.
- * Return whether the list changed as a result.
- * java.util.List#addAll(java.lang.Iterable iterable)
- */
- public static <E> boolean addAll(List<? super E> list, int index, Iterable<E> iterable, int size) {
- return addAll(list, index, iterable.iterator(), size);
- }
-
- /**
- * Add all the elements returned by the specified iterator
- * to the specified list at the specified index.
- * Return whether the list changed as a result.
- * java.util.List#addAll(java.util.Iterator iterator)
- */
- public static <E> boolean addAll(List<? super E> list, int index, Iterator<? extends E> iterator) {
- return (iterator.hasNext()) ? list.addAll(index, list(iterator)) : false;
- }
-
- /**
- * Add all the elements returned by the specified iterator
- * to the specified list at the specified index.
- * Return whether the list changed as a result.
- * java.util.List#addAll(java.util.Iterator iterator)
- */
- public static <E> boolean addAll(List<? super E> list, int index, Iterator<? extends E> iterator, int size) {
- return (iterator.hasNext()) ? list.addAll(index, list(iterator, size)) : false;
- }
-
- /**
- * Add all the elements in the specified array
- * to the specified list at the specified index.
- * Return whether the list changed as a result.
- * java.util.List#addAll(Object[] array)
- */
- public static <E> boolean addAll(List<? super E> list, int index, E[] array) {
- return (array.length == 0) ? false : list.addAll(index, Arrays.asList(array));
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the elements
- * in the specified collection.
- * java.util.Arrays#addAll(Object[] array, java.util.Collection c)
- */
- public static <E> E[] addAll(E[] array, Collection<? extends E> collection) {
- int size = collection.size();
- return (size == 0) ? array : addAll(array, collection, size);
- }
-
- /**
- * assume collection is non-empty
- */
- private static <E> E[] addAll_(E[] array, Collection<? extends E> collection) {
- return addAll(array, collection, collection.size());
- }
-
- /**
- * assume collection is non-empty
- */
- private static <E> E[] addAll(E[] array, Collection<? extends E> collection, int collectionSize) {
- int len = array.length;
- E[] result = newArray(array, len + collectionSize);
- if (len > 0) {
- System.arraycopy(array, 0, result, 0, len);
- }
- int i = len;
- for (E item : collection) {
- result[i++] = item;
- }
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the elements
- * in the specified iterable.
- * java.util.Arrays#addAll(Object[] array, java.lang.Iterable iterable)
- */
- public static <E> E[] addAll(E[] array, Iterable<? extends E> iterable) {
- return addAll(array, iterable.iterator());
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the elements
- * in the specified iterable.
- * java.util.Arrays#addAll(Object[] array, java.lang.Iterable iterable)
- */
- public static <E> E[] addAll(E[] array, Iterable<? extends E> iterable, int size) {
- return addAll(array, iterable.iterator(), size);
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the elements
- * in the specified iterator.
- * java.util.Arrays#addAll(Object[] array, java.util.Iterator iterator)
- */
- public static <E> E[] addAll(E[] array, Iterator<? extends E> iterator) {
- return (iterator.hasNext()) ? addAll_(array, list(iterator)) : array;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array followed by the elements
- * in the specified iterator.
- * java.util.Arrays#addAll(Object[] array, java.util.Iterator iterator)
- */
- public static <E> E[] addAll(E[] array, Iterator<? extends E> iterator, int size) {
- return (iterator.hasNext()) ? addAll_(array, list(iterator, size)) : array;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array 1 followed by the elements
- * in the specified array 2.
- * java.util.Arrays#addAll(Object[] array1, Object[] array2)
- */
- public static <E> E[] addAll(E[] array1, E[] array2) {
- int array2Length = array2.length;
- return (array2Length == 0) ? array1 : addAll(array1, array2, array2Length);
- }
-
- /**
- * assume array2Length > 0
- */
- private static <E> E[] addAll(E[] array1, E[] array2, int array2Length) {
- int array1Length = array1.length;
- return (array1Length == 0) ? array2 : addAll(array1, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static <E> E[] addAll(E[] array1, E[] array2, int array1Length, int array2Length) {
- E[] result = newArray(array1, array1Length + array2Length);
- System.arraycopy(array1, 0, result, 0, array1Length);
- System.arraycopy(array2, 0, result, array1Length, array2Length);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * first specified array with the objects in the second
- * specified array added at the specified index.
- * java.util.Arrays#add(Object[] array1, int index, Object[] array2)
- */
- public static <E> E[] addAll(E[] array1, int index, E[] array2) {
- int array2Length = array2.length;
- return (array2Length == 0) ? array1 : addAll(array1, index, array2, array2Length);
- }
-
- /**
- * assume array2Length > 0
- */
- private static <E> E[] addAll(E[] array1, int index, E[] array2, int array2Length) {
- int array1Length = array1.length;
- return (index == array1Length) ? // array2 added to end of array1
- (array1Length == 0) ? array2 : addAll(array1, array2, array1Length, array2Length)
- :
- addAll(array1, index, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static <E> E[] addAll(E[] array1, int index, E[] array2, int array1Length, int array2Length) {
- E[] result = newArray(array1, array1Length + array2Length);
- System.arraycopy(array1, 0, result, 0, index);
- System.arraycopy(array2, 0, result, index, array2Length);
- System.arraycopy(array1, index, result, index + array2Length, array1Length - index);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the elements
- * in the specified collection inserted at the specified index.
- * java.util.Arrays#addAll(Object[] array, int index, java.util.Collection c)
- */
- public static <E> E[] addAll(E[] array, int index, Collection<? extends E> collection) {
- int size = collection.size();
- return (size == 0) ? array : addAll(array, index, collection, size);
- }
-
- /**
- * assume collection is non-empty
- */
- private static <E> E[] addAll_(E[] array, int index, Collection<? extends E> collection) {
- return addAll(array, index, collection, collection.size());
- }
-
- /**
- * assume collection is non-empty
- */
- private static <E> E[] addAll(E[] array, int index, Collection<? extends E> collection, int collectionSize) {
- int arrayLength = array.length;
- E[] result = newArray(array, arrayLength + collectionSize);
- if ((arrayLength == 0) && (index == 0)) {
- return collection.toArray(result);
- }
- System.arraycopy(array, 0, result, 0, index);
- int i = index;
- for (E item : collection) {
- result[i++] = item;
- }
- System.arraycopy(array, index, result, index + collectionSize, arrayLength - index);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the elements
- * in the specified iterable inserted at the specified index.
- * java.util.Arrays#addAll(Object[] array, int index, java.lang.Iterable iterable)
- */
- public static <E> E[] addAll(E[] array, int index, Iterable<? extends E> iterable) {
- return addAll(array, index, iterable.iterator());
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the elements
- * in the specified iterable inserted at the specified index.
- * java.util.Arrays#addAll(Object[] array, int index, java.lang.Iterable iterable)
- */
- public static <E> E[] addAll(E[] array, int index, Iterable<? extends E> iterable, int size) {
- return addAll(array, index, iterable.iterator(), size);
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the elements
- * in the specified iterator inserted at the specified index.
- * java.util.Arrays#addAll(Object[] array, int index, java.util.Iterator iterator)
- */
- public static <E> E[] addAll(E[] array, int index, Iterator<? extends E> iterator) {
- return (iterator.hasNext()) ? addAll_(array, index, list(iterator)) : array;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the elements
- * in the specified iterator inserted at the specified index.
- * java.util.Arrays#addAll(Object[] array, int index, java.util.Iterator iterator)
- */
- public static <E> E[] addAll(E[] array, int index, Iterator<? extends E> iterator, int size) {
- return (iterator.hasNext()) ? addAll_(array, index, list(iterator, size)) : array;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array 1 followed by the elements
- * in the specified array 2.
- * java.util.Arrays#addAll(char[] array1, char[] array2)
- */
- public static char[] addAll(char[] array1, char[] array2) {
- int array2Length = array2.length;
- return (array2Length == 0) ? array1 : addAll(array1, array2, array2Length);
- }
-
- /**
- * assume array2Length > 0
- */
- private static char[] addAll(char[] array1, char[] array2, int array2Length) {
- int array1Length = array1.length;
- return (array1Length == 0) ? array2 : addAll(array1, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static char[] addAll(char[] array1, char[] array2, int array1Length, int array2Length) {
- char[] result = new char[array1Length + array2Length];
- System.arraycopy(array1, 0, result, 0, array1Length);
- System.arraycopy(array2, 0, result, array1Length, array2Length);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * first specified array with the objects in the second
- * specified array added at the specified index.
- * java.util.Arrays#add(char[] array1, int index, char[] array2)
- */
- public static char[] addAll(char[] array1, int index, char[] array2) {
- int array2Length = array2.length;
- return (array2Length == 0) ? array1 : addAll(array1, index, array2, array2Length);
- }
-
- /**
- * assume array2Length > 0
- */
- private static char[] addAll(char[] array1, int index, char[] array2, int array2Length) {
- int array1Length = array1.length;
- return (index == array1Length) ? // array2 added to end of array1
- (array1Length == 0) ? array2 : addAll(array1, array2, array1Length, array2Length)
- :
- addAll(array1, index, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static char[] addAll(char[] array1, int index, char[] array2, int array1Length, int array2Length) {
- char[] result = new char[array1Length + array2Length];
- System.arraycopy(array1, 0, result, 0, index);
- System.arraycopy(array2, 0, result, index, array2Length);
- System.arraycopy(array1, index, result, index + array2Length, array1Length - index);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array 1 followed by the elements
- * in the specified array 2.
- * java.util.Arrays#addAll(int[] array1, int[] array2)
- */
- public static int[] addAll(int[] array1, int[] array2) {
- int array2Length = array2.length;
- return (array2Length == 0) ? array1 : addAll(array1, array2, array2Length);
- }
-
- /**
- * assume array2Length > 0
- */
- private static int[] addAll(int[] array1, int[] array2, int array2Length) {
- int array1Length = array1.length;
- return (array1Length == 0) ? array2 : addAll(array1, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static int[] addAll(int[] array1, int[] array2, int array1Length, int array2Length) {
- int[] result = new int[array1Length + array2Length];
- System.arraycopy(array1, 0, result, 0, array1Length);
- System.arraycopy(array2, 0, result, array1Length, array2Length);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * first specified array with the objects in the second
- * specified array added at the specified index.
- * java.util.Arrays#add(int[] array1, int index, int[] array2)
- */
- public static int[] addAll(int[] array1, int index, int[] array2) {
- int array2Length = array2.length;
- return (array2Length == 0) ? array1 : addAll(array1, index, array2, array2Length);
- }
-
- /**
- * assume array2Length > 0
- */
- private static int[] addAll(int[] array1, int index, int[] array2, int array2Length) {
- int array1Length = array1.length;
- return (index == array1Length) ? // array2 added to end of array1
- (array1Length == 0) ? array2 : addAll(array1, array2, array1Length, array2Length)
- :
- addAll(array1, index, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static int[] addAll(int[] array1, int index, int[] array2, int array1Length, int array2Length) {
- int[] result = new int[array1Length + array2Length];
- System.arraycopy(array1, 0, result, 0, index);
- System.arraycopy(array2, 0, result, index, array2Length);
- System.arraycopy(array1, index, result, index + array2Length, array1Length - index);
- return result;
- }
-
- /**
- * Return an array corresponding to the specified iterable.
- * @see java.util.Collection#toArray()
- * java.lang.Iterable#toArray()
- */
- public static Object[] array(Iterable<?> iterable) {
- return array(iterable.iterator());
- }
-
- /**
- * Return an array corresponding to the specified iterable.
- * @see java.util.Collection#toArray()
- * java.lang.Iterable#toArray()
- */
- public static Object[] array(Iterable<?> iterable, int size) {
- return array(iterable.iterator(), size);
- }
-
- /**
- * Return an array corresponding to the specified iterable;
- * the runtime type of the returned array is that of the specified array.
- * If the collection fits in the specified array, it is returned therein.
- * Otherwise, a new array is allocated with the runtime type of the
- * specified array and the size of this collection.
- * @see java.util.Collection#toArray(java.lang.Object[])
- * java.lang.Iterable#toArray(Object[])
- */
- public static <E> E[] array(Iterable<? extends E> iterable, E[] array) {
- return array(iterable.iterator(), array);
- }
-
- /**
- * Return an array corresponding to the specified iterable;
- * the runtime type of the returned array is that of the specified array.
- * If the collection fits in the specified array, it is returned therein.
- * Otherwise, a new array is allocated with the runtime type of the
- * specified array and the size of this collection.
- * @see java.util.Collection#toArray(java.lang.Object[])
- * java.lang.Iterable#toArray(Object[])
- */
- public static <E> E[] array(Iterable<? extends E> iterable, int size, E[] array) {
- return array(iterable.iterator(), size, array);
- }
-
- /**
- * Return an array corresponding to the specified iterator.
- * @see java.util.Collection#toArray()
- * java.util.Iterator#toArray()
- */
- public static Object[] array(Iterator<?> iterator) {
- return (iterator.hasNext()) ? list(iterator).toArray() : EMPTY_OBJECT_ARRAY;
- }
- private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
-
- /**
- * Return an array corresponding to the specified iterator.
- * @see java.util.Collection#toArray()
- * java.util.Iterator#toArray()
- */
- public static Object[] array(Iterator<?> iterator, int size) {
- return (iterator.hasNext()) ? list(iterator, size).toArray() : EMPTY_OBJECT_ARRAY;
- }
-
- /**
- * Return an array corresponding to the specified iterator;
- * the runtime type of the returned array is that of the specified array.
- * If the collection fits in the specified array, it is returned therein.
- * Otherwise, a new array is allocated with the runtime type of the
- * specified array and the size of this collection.
- * @see java.util.Collection#toArray(java.lang.Object[])
- * java.util.Iterator#toArray(Object[])
- */
- public static <E> E[] array(Iterator<? extends E> iterator, E[] array) {
- return (iterator.hasNext()) ? list(iterator).toArray(array) : newArray(array, 0);
- }
-
- /**
- * Return an array corresponding to the specified iterator;
- * the runtime type of the returned array is that of the specified array.
- * If the collection fits in the specified array, it is returned therein.
- * Otherwise, a new array is allocated with the runtime type of the
- * specified array and the size of this collection.
- * @see java.util.Collection#toArray(java.lang.Object[])
- * java.util.Iterator#toArray(Object[])
- */
- public static <E> E[] array(Iterator<? extends E> iterator, int size, E[] array) {
- return (iterator.hasNext()) ? list(iterator, size).toArray(array) : newArray(array, 0);
- }
-
- /**
- * Return a bag corresponding to the specified enumeration.
- * HashBag(java.util.Enumeration enumeration)
- */
- public static <E> HashBag<E> bag(Enumeration<? extends E> enumeration) {
- return bag(enumeration, new HashBag<E>());
- }
-
- /**
- * Return a bag corresponding to the specified enumeration.
- * HashBag(java.util.Enumeration enumeration)
- */
- public static <E> HashBag<E> bag(Enumeration<? extends E> enumeration, int size) {
- return bag(enumeration, new HashBag<E>(size));
- }
-
- private static <E> HashBag<E> bag(Enumeration<? extends E> enumeration, HashBag<E> bag) {
- while (enumeration.hasMoreElements()) {
- bag.add(enumeration.nextElement());
- }
- return bag;
- }
-
- /**
- * Return a bag corresponding to the specified iterable.
- * HashBag(java.lang.Iterable iterable)
- */
- public static <E> HashBag<E> bag(Iterable<? extends E> iterable) {
- return bag(iterable.iterator());
- }
-
- /**
- * Return a bag corresponding to the specified iterable.
- * HashBag(java.lang.Iterable iterable)
- */
- public static <E> HashBag<E> bag(Iterable<? extends E> iterable, int size) {
- return bag(iterable.iterator(), size);
- }
-
- /**
- * Return a bag corresponding to the specified iterator.
- * HashBag(java.util.Iterator iterator)
- */
- public static <E> HashBag<E> bag(Iterator<? extends E> iterator) {
- return bag(iterator, new HashBag<E>());
- }
-
- /**
- * Return a bag corresponding to the specified iterator.
- * HashBag(java.util.Iterator iterator)
- */
- public static <E> HashBag<E> bag(Iterator<? extends E> iterator, int size) {
- return bag(iterator, new HashBag<E>(size));
- }
-
- private static <E> HashBag<E> bag(Iterator<? extends E> iterator, HashBag<E> bag) {
- while (iterator.hasNext()) {
- bag.add(iterator.next());
- }
- return bag;
- }
-
- /**
- * Return a bag corresponding to the specified array.
- * HashBag(Object[] array)
- */
- public static <E> HashBag<E> bag(E... array) {
- int len = array.length;
- HashBag<E> bag = new HashBag<E>(len);
- for (E item : array) {
- bag.add(item);
- }
- return bag;
- }
-
- /**
- * Clear the specified array.
- * java.util.Arrays#clear(Object[] array)
- */
- public static <E> E[] clear(E[] array) {
- if (array.length == 0) {
- return array;
- }
- return newArray(array, 0);
- }
-
- /**
- * Return a collection corresponding to the specified enumeration.
- */
- public static <E> HashBag<E> collection(Enumeration<? extends E> enumeration) {
- return bag(enumeration);
- }
-
- /**
- * Return a collection corresponding to the specified enumeration.
- */
- public static <E> HashBag<E> collection(Enumeration<? extends E> enumeration, int size) {
- return bag(enumeration, size);
- }
-
- /**
- * Return a collection corresponding to the specified iterable.
- */
- public static <E> HashBag<E> collection(Iterable<? extends E> iterable) {
- return collection(iterable.iterator());
- }
-
- /**
- * Return a collection corresponding to the specified iterable.
- */
- public static <E> HashBag<E> collection(Iterable<? extends E> iterable, int size) {
- return collection(iterable.iterator(), size);
- }
-
- /**
- * Return a collection corresponding to the specified iterator.
- */
- public static <E> HashBag<E> collection(Iterator<? extends E> iterator) {
- return bag(iterator);
- }
-
- /**
- * Return a collection corresponding to the specified iterator.
- */
- public static <E> HashBag<E> collection(Iterator<? extends E> iterator, int size) {
- return bag(iterator, size);
- }
-
- /**
- * Return a collection corresponding to the specified array.
- */
- public static <E> HashBag<E> collection(E... array) {
- return bag(array);
- }
-
- /**
- * Return whether the specified enumeration contains the
- * specified element.
- * java.util.Enumeration#contains(Object o)
- */
- public static boolean contains(Enumeration<?> enumeration, Object value) {
- if (value == null) {
- while (enumeration.hasMoreElements()) {
- if (enumeration.nextElement() == null) {
- return true;
- }
- }
- } else {
- while (enumeration.hasMoreElements()) {
- if (value.equals(enumeration.nextElement())) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified iterable contains the
- * specified element.
- * java.lang.Iterable#contains(Object o)
- */
- public static boolean contains(Iterable<?> iterable, Object value) {
- return contains(iterable.iterator(), value);
- }
-
- /**
- * Return whether the specified iterator contains the
- * specified element.
- * java.util.Iterator#contains(Object o)
- */
- public static boolean contains(Iterator<?> iterator, Object value) {
- if (value == null) {
- while (iterator.hasNext()) {
- if (iterator.next() == null) {
- return true;
- }
- }
- } else {
- while (iterator.hasNext()) {
- if (value.equals(iterator.next())) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified array contains the
- * specified element.
- * java.util.Arrays#contains(Object[] array, Object o)
- */
- public static boolean contains(Object[] array, Object value) {
- if (value == null) {
- for (int i = array.length; i-- > 0; ) {
- if (array[i] == null) {
- return true;
- }
- }
- } else {
- for (int i = array.length; i-- > 0; ) {
- if (value.equals(array[i])) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified array contains the
- * specified element.
- * java.util.Arrays#contains(char[] array, char value)
- */
- public static boolean contains(char[] array, char value) {
- return contains(array, value, array.length);
- }
-
- private static boolean contains(char[] array, char value, int arrayLength) {
- for (int i = arrayLength; i-- > 0; ) {
- if (array[i] == value) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified array contains the
- * specified element.
- * java.util.Arrays#contains(int[] array, int value)
- */
- public static boolean contains(int[] array, int value) {
- return contains(array, value, array.length);
- }
-
- private static boolean contains(int[] array, int value, int arrayLength) {
- for (int i = arrayLength; i-- > 0; ) {
- if (array[i] == value) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return whether the specified collection contains all of the
- * elements in the specified iterable.
- * java.util.Collection#containsAll(java.lang.Iterable iterable)
- */
- public static boolean containsAll(Collection<?> collection, Iterable<?> iterable) {
- return containsAll(collection, iterable.iterator());
- }
-
- /**
- * Return whether the specified collection contains all of the
- * elements in the specified iterator.
- * java.util.Collection#containsAll(java.util.Iterator iterator)
- */
- public static boolean containsAll(Collection<?> collection, Iterator<?> iterator) {
- while (iterator.hasNext()) {
- if ( ! collection.contains(iterator.next())) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified collection contains all of the
- * elements in the specified array.
- * java.util.Collection#containsAll(Object[] array)
- */
- public static boolean containsAll(Collection<?> collection, Object[] array) {
- for (int i = array.length; i-- > 0; ) {
- if ( ! collection.contains(array[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified iterable contains all of the
- * elements in the specified collection.
- * java.lang.Iterable#containsAll(java.util.Collection collection)
- */
- public static boolean containsAll(Iterable<?> iterable, Collection<?> collection) {
- return containsAll(iterable.iterator(), collection);
- }
-
- /**
- * Return whether the specified iterable contains all of the
- * elements in the specified collection.
- * java.lang.Iterable#containsAll(java.util.Collection collection)
- */
- public static boolean containsAll(Iterable<?> iterable, int size, Collection<?> collection) {
- return containsAll(iterable.iterator(), size, collection);
- }
-
- /**
- * Return whether the specified iterable 1 contains all of the
- * elements in the specified iterable 2.
- * java.lang.Iterable#containsAll(java.lang.Iterable iterable)
- */
- public static boolean containsAll(Iterable<?> iterable1, Iterable<?> iterable2) {
- return containsAll(iterable1.iterator(), iterable2.iterator());
- }
-
- /**
- * Return whether the specified iterable 1 contains all of the
- * elements in the specified iterable 2.
- * java.lang.Iterable#containsAll(java.lang.Iterable iterable)
- */
- public static boolean containsAll(Iterable<?> iterable1, int size, Iterable<?> iterable2) {
- return containsAll(iterable1.iterator(), size, iterable2.iterator());
- }
-
- /**
- * Return whether the specified iterable contains all of the
- * elements in the specified iterator.
- * java.lang.Iterable#containsAll(java.util.Iterator iterator)
- */
- public static boolean containsAll(Iterable<?> iterable, Iterator<?> iterator) {
- return containsAll(iterable.iterator(), iterator);
- }
-
- /**
- * Return whether the specified iterable contains all of the
- * elements in the specified iterator.
- * java.lang.Iterable#containsAll(java.util.Iterator iterator)
- */
- public static boolean containsAll(Iterable<?> iterable, int size, Iterator<?> iterator) {
- return containsAll(iterable.iterator(), size, iterator);
- }
-
- /**
- * Return whether the specified iterable contains all of the
- * elements in the specified array.
- * java.lang.Iterable#containsAll(Object[] array)
- */
- public static boolean containsAll(Iterable<?> iterable, Object[] array) {
- return containsAll(iterable.iterator(), array);
- }
-
- /**
- * Return whether the specified iterable contains all of the
- * elements in the specified array.
- * java.lang.Iterable#containsAll(Object[] array)
- */
- public static boolean containsAll(Iterable<?> iterable, int size, Object[] array) {
- return containsAll(iterable.iterator(), size, array);
- }
-
- /**
- * Return whether the specified iterator contains all of the
- * elements in the specified collection.
- * java.util.Iterator#containsAll(java.util.Collection collection)
- */
- public static boolean containsAll(Iterator<?> iterator, Collection<?> collection) {
- return collection(iterator).containsAll(collection);
- }
-
- /**
- * Return whether the specified iterator contains all of the
- * elements in the specified collection.
- * java.util.Iterator#containsAll(java.util.Collection collection)
- */
- public static boolean containsAll(Iterator<?> iterator, int size, Collection<?> collection) {
- return collection(iterator, size).containsAll(collection);
- }
-
- /**
- * Return whether the specified iterator contains all of the
- * elements in the specified iterable.
- * java.util.Iterator#containsAll(java.lang.Iterable iterable)
- */
- public static boolean containsAll(Iterator<?> iterator, Iterable<?> iterable) {
- return containsAll(collection(iterator), iterable);
- }
-
- /**
- * Return whether the specified iterator contains all of the
- * elements in the specified iterable.
- * java.util.Iterator#containsAll(java.lang.Iterable iterable)
- */
- public static boolean containsAll(Iterator<?> iterator, int size, Iterable<?> iterable) {
- return containsAll(collection(iterator, size), iterable);
- }
-
- /**
- * Return whether the specified iterator 1 contains all of the
- * elements in the specified iterator 2.
- * java.util.Iterator#containsAll(java.util.Iterator iterator)
- */
- public static boolean containsAll(Iterator<?> iterator1, Iterator<?> iterator2) {
- return containsAll(collection(iterator1), iterator2);
- }
-
- /**
- * Return whether the specified iterator 1 contains all of the
- * elements in the specified iterator 2.
- * java.util.Iterator#containsAll(java.util.Iterator iterator)
- */
- public static boolean containsAll(Iterator<?> iterator1, int size, Iterator<?> iterator2) {
- return containsAll(collection(iterator1, size), iterator2);
- }
-
- /**
- * Return whether the specified iterator contains all of the
- * elements in the specified array.
- * java.util.Iterator#containsAll(Object[] array)
- */
- public static boolean containsAll(Iterator<?> iterator, Object[] array) {
- return containsAll(collection(iterator), array);
- }
-
- /**
- * Return whether the specified iterator contains all of the
- * elements in the specified array.
- * java.util.Iterator#containsAll(Object[] array)
- */
- public static boolean containsAll(Iterator<?> iterator, int size, Object[] array) {
- return containsAll(collection(iterator, size), array);
- }
-
- /**
- * Return whether the specified array contains all of the
- * elements in the specified collection.
- * java.util.Arrays#containsAll(Object[] array, java.util.Collection collection)
- */
- public static boolean containsAll(Object[] array, Collection<?> collection) {
- return containsAll(array, collection.iterator());
- }
-
- /**
- * Return whether the specified array contains all of the
- * elements in the specified iterable.
- * java.util.Arrays#containsAll(Object[] array, java.lang.Iterable iterable)
- */
- public static boolean containsAll(Object[] array, Iterable<?> iterable) {
- return containsAll(array, iterable.iterator());
- }
-
- /**
- * Return whether the specified array contains all of the
- * elements in the specified iterator.
- * java.util.Arrays#containsAll(Object[] array, java.util.Iterator iterator)
- */
- public static boolean containsAll(Object[] array, Iterator<?> iterator) {
- while (iterator.hasNext()) {
- if ( ! contains(array, iterator.next())) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified array 1 contains all of the
- * elements in the specified array 2.
- * java.util.Arrays#containsAll(Object[] array1, Object[] array2)
- */
- public static boolean containsAll(Object[] array1, Object[] array2) {
- for (int i = array2.length; i-- > 0; ) {
- if ( ! contains(array1, array2[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified array 1 contains all of the
- * elements in the specified array 2.
- * java.util.Arrays#containsAll(char[] array1, char[] array2)
- */
- public static boolean containsAll(char[] array1, char[] array2) {
- for (int i = array2.length; i-- > 0; ) {
- if ( ! contains(array1, array2[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified array 1 contains all of the
- * elements in the specified array 2.
- * java.util.Arrays#containsAll(int[] array1, int[] array2)
- */
- public static boolean containsAll(int[] array1, int[] array2) {
- for (int i = array2.length; i-- > 0; ) {
- if ( ! contains(array1, array2[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return the index of the first elements in the specified
- * arrays that are different, beginning at the end.
- * If the arrays are identical, return -1.
- * If the arrays are different sizes, return the index of the
- * last element in the longer array.
- * Use the elements' #equals() method to compare the
- * elements.
- */
- public static int diffEnd(Object[] array1, Object[] array2) {
- return diffEnd(Arrays.asList(array1), Arrays.asList(array2));
- }
-
- /**
- * Return the index of the first elements in the specified
- * lists that are different, beginning at the end.
- * If the lists are identical, return -1.
- * If the lists are different sizes, return the index of the
- * last element in the longer list.
- * Use the elements' #equals() method to compare the
- * elements.
- */
- public static int diffEnd(List<?> list1, List<?> list2) {
- int size1 = list1.size();
- int size2 = list2.size();
- if (size1 != size2) {
- return Math.max(size1, size2) - 1;
- }
- int end = size1 - 1;
- while (end > -1) {
- Object o = list1.get(end);
- if (o == null) {
- if (list2.get(end) == null) {
- end--;
- } else {
- return end;
- }
- } else {
- if (o.equals(list2.get(end))) {
- end--;
- } else {
- return end;
- }
- }
- }
- return end;
- }
-
- /**
- * Return the range of elements in the specified
- * arrays that are different.
- * If the arrays are identical, return [size, -1].
- * Use the elements' #equals() method to compare the
- * elements.
- * @see #diffStart(Object[], Object[])
- * @see #diffEnd(Object[], Object[])
- */
- public static Range diffRange(Object[] array1, Object[] array2) {
- return diffRange(Arrays.asList(array1), Arrays.asList(array2));
- }
-
- /**
- * Return the range of elements in the specified
- * arrays that are different.
- * If the arrays are identical, return [size, -1].
- * Use the elements' #equals() method to compare the
- * elements.
- * @see #diffStart(java.util.List, java.util.List)
- * @see #diffEnd(java.util.List, java.util.List)
- */
- public static Range diffRange(List<?> list1, List<?> list2) {
- int end = diffEnd(list1, list2);
- if (end == -1) {
- // the lists are identical, the start is the size of the two lists
- return new Range(list1.size(), end);
- }
- // the lists are different, calculate the start of the range
- return new Range(diffStart(list1, list2), end);
- }
-
- /**
- * Return the index of the first elements in the specified
- * arrays that are different. If the arrays are identical, return
- * the size of the two arrays (i.e. one past the last index).
- * If the arrays are different sizes and all the elements in
- * the shorter array match their corresponding elements in
- * the longer array, return the size of the shorter array
- * (i.e. one past the last index of the shorter array).
- * Use the elements' #equals() method to compare the
- * elements.
- */
- public static int diffStart(Object[] array1, Object[] array2) {
- return diffStart(Arrays.asList(array1), Arrays.asList(array2));
- }
-
- /**
- * Return the index of the first elements in the specified
- * lists that are different. If the lists are identical, return
- * the size of the two lists (i.e. one past the last index).
- * If the lists are different sizes and all the elements in
- * the shorter list match their corresponding elements in
- * the longer list, return the size of the shorter list
- * (i.e. one past the last index of the shorter list).
- * Use the elements' #equals() method to compare the
- * elements.
- */
- public static int diffStart(List<?> list1, List<?> list2) {
- int end = Math.min(list1.size(), list2.size());
- int start = 0;
- while (start < end) {
- Object o = list1.get(start);
- if (o == null) {
- if (list2.get(start) == null) {
- start++;
- } else {
- return start;
- }
- } else {
- if (o.equals(list2.get(start))) {
- start++;
- } else {
- return start;
- }
- }
- }
- return start;
- }
-
- /**
- * Return whether the specified iterators return equal elements.
- * java.util.Iterator#equals(java.util.Iterator iterator)
- */
- public static boolean equals(Iterator<?> iterator1, Iterator<?> iterator2) {
- while (iterator1.hasNext() && iterator2.hasNext()) {
- Object o1 = iterator1.next();
- Object o2 = iterator2.next();
- if ( ! (o1 == null ? o2 == null : o1.equals(o2))) {
- return false;
- }
- }
- return ! (iterator1.hasNext() || iterator2.hasNext());
- }
-
- /**
- * Return the element corresponding to the specified index
- * in the specified iterator.
- * java.util.ListIterator#get(int index)
- */
- public static <E> E get(ListIterator<? extends E> iterator, int index) {
- while (iterator.hasNext()) {
- E next = iterator.next();
- if (iterator.previousIndex() == index) {
- return next;
- }
- }
- throw new IndexOutOfBoundsException(String.valueOf(index) + ':' + String.valueOf(iterator.previousIndex()));
- }
-
- /**
- * Return whether the specified arrays contain the same elements.
- * java.util.Arrays#identical(Object[] array1, Object[] array2)
- */
- public static boolean identical(Object[] array1, Object[] array2) {
- if (array1 == array2) {
- return true;
- }
- if (array1 == null || array2 == null) {
- return false;
- }
- int length = array1.length;
- if (array2.length != length) {
- return false;
- }
- for (int i = length; i-- > 0; ) {
- if (array1[i] != array2[i]) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified iterators return the same elements.
- * java.util.Iterator#identical(java.util.Iterator iterator)
- */
- public static boolean identical(Iterator<?> iterator1, Iterator<?> iterator2) {
- while (iterator1.hasNext() && iterator2.hasNext()) {
- if (iterator1.next() != iterator2.next()) {
- return false;
- }
- }
- return ! (iterator1.hasNext() || iterator2.hasNext());
- }
-
- /**
- * Return the index of the first elements in the specified
- * arrays that are different, beginning at the end.
- * If the arrays are identical, return -1.
- * If the arrays are different sizes, return the index of the
- * last element in the longer array.
- * Use object identity to compare the elements.
- */
- public static int identityDiffEnd(Object[] array1, Object[] array2) {
- return identityDiffEnd(Arrays.asList(array1), Arrays.asList(array2));
- }
-
- /**
- * Return the index of the first elements in the specified
- * lists that are different, beginning at the end.
- * If the lists are identical, return -1.
- * If the lists are different sizes, return the index of the
- * last element in the longer list.
- * Use object identity to compare the elements.
- */
- public static int identityDiffEnd(List<?> list1, List<?> list2) {
- int size1 = list1.size();
- int size2 = list2.size();
- if (size1 != size2) {
- return Math.max(size1, size2) - 1;
- }
- int end = size1 - 1;
- while (end > -1) {
- if (list1.get(end) == list2.get(end)) {
- end--;
- } else {
- return end;
- }
- }
- return end;
- }
-
- /**
- * Return the range of elements in the specified
- * arrays that are different.
- * If the arrays are identical, return [size, -1].
- * Use object identity to compare the elements.
- * @see #identityDiffStart(Object[], Object[])
- * @see #identityDiffEnd(Object[], Object[])
- */
- public static Range identityDiffRange(Object[] array1, Object[] array2) {
- return identityDiffRange(Arrays.asList(array1), Arrays.asList(array2));
- }
-
- /**
- * Return the range of elements in the specified
- * arrays that are different.
- * If the arrays are identical, return [size, -1].
- * Use object identity to compare the elements.
- * @see #identityDiffStart(java.util.List, java.util.List)
- * @see #identityDiffEnd(java.util.List, java.util.List)
- */
- public static Range identityDiffRange(List<?> list1, List<?> list2) {
- int end = identityDiffEnd(list1, list2);
- if (end == -1) {
- // the lists are identical, the start is the size of the two lists
- return new Range(list1.size(), end);
- }
- // the lists are different, calculate the start of the range
- return new Range(identityDiffStart(list1, list2), end);
- }
-
- /**
- * Return the index of the first elements in the specified
- * arrays that are different. If the arrays are identical, return
- * the size of the two arrays (i.e. one past the last index).
- * If the arrays are different sizes and all the elements in
- * the shorter array match their corresponding elements in
- * the longer array, return the size of the shorter array
- * (i.e. one past the last index of the shorter array).
- * Use object identity to compare the elements.
- */
- public static int identityDiffStart(Object[] array1, Object[] array2) {
- return identityDiffStart(Arrays.asList(array1), Arrays.asList(array2));
- }
-
- /**
- * Return the index of the first elements in the specified
- * lists that are different. If the lists are identical, return
- * the size of the two lists (i.e. one past the last index).
- * If the lists are different sizes and all the elements in
- * the shorter list match their corresponding elements in
- * the longer list, return the size of the shorter list
- * (i.e. one past the last index of the shorter list).
- * Use object identity to compare the elements.
- */
- public static int identityDiffStart(List<?> list1, List<?> list2) {
- int end = Math.min(list1.size(), list2.size());
- int start = 0;
- while (start < end) {
- if (list1.get(start) == list2.get(start)) {
- start++;
- } else {
- return start;
- }
- }
- return start;
- }
-
- /**
- * Return the index of the first occurrence of the
- * specified element in the specified iterator,
- * or return -1 if there is no such index.
- * java.util.Iterator#indexOf(Object o)
- */
- public static int indexOf(Iterator<?> iterator, Object value) {
- if (value == null) {
- for (int i = 0; iterator.hasNext(); i++) {
- if (iterator.next() == null) {
- return i;
- }
- }
- } else {
- for (int i = 0; iterator.hasNext(); i++) {
- if (value.equals(iterator.next())) {
- return i;
- }
- }
- }
- return -1;
- }
-
- /**
- * Return the index of the first occurrence of the
- * specified element in the specified array,
- * or return -1 if there is no such index.
- * java.util.Arrays#indexOf(Object[] array, Object o)
- */
- public static int indexOf(Object[] array, Object value) {
- int len = array.length;
- if (value == null) {
- for (int i = 0; i < len; i++) {
- if (array[i] == null) {
- return i;
- }
- }
- } else {
- for (int i = 0; i < len; i++) {
- if (value.equals(array[i])) {
- return i;
- }
- }
- }
- return -1;
- }
-
- /**
- * Return the index of the first occurrence of the
- * specified element in the specified array,
- * or return -1 if there is no such index.
- * java.util.Arrays#indexOf(char[] array, char value)
- */
- public static int indexOf(char[] array, char value) {
- int len = array.length;
- for (int i = 0; i < len; i++) {
- if (array[i] == value) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Return the index of the first occurrence of the
- * specified element in the specified array,
- * or return -1 if there is no such index.
- * java.util.Arrays#indexOf(int[] array, int value)
- */
- public static int indexOf(int[] array, int value) {
- int len = array.length;
- for (int i = 0; i < len; i++) {
- if (array[i] == value) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Return the maximum index of where the specified comparable object
- * should be inserted into the specified sorted list and still keep
- * the list sorted.
- */
- public static <E extends Comparable<? super E>> int insertionIndexOf(List<E> sortedList, Comparable<E> value) {
- int len = sortedList.size();
- for (int i = 0; i < len; i++) {
- if (value.compareTo(sortedList.get(i)) < 0) {
- return i;
- }
- }
- return len;
- }
-
- /**
- * Return the maximum index of where the specified object
- * should be inserted into the specified sorted list and still keep
- * the list sorted.
- */
- public static <E> int insertionIndexOf(List<E> sortedList, E value, Comparator<? super E> comparator) {
- int len = sortedList.size();
- for (int i = 0; i < len; i++) {
- if (comparator.compare(value, sortedList.get(i)) < 0) {
- return i;
- }
- }
- return len;
- }
-
- /**
- * Return the maximum index of where the specified comparable object
- * should be inserted into the specified sorted array and still keep
- * the array sorted.
- */
- public static <E extends Comparable<? super E>> int insertionIndexOf(E[] sortedArray, Comparable<E> value) {
- int len = sortedArray.length;
- for (int i = 0; i < len; i++) {
- if (value.compareTo(sortedArray[i]) < 0) {
- return i;
- }
- }
- return len;
- }
-
- /**
- * Return the maximum index of where the specified comparable object
- * should be inserted into the specified sorted array and still keep
- * the array sorted.
- */
- public static <E> int insertionIndexOf(E[] sortedArray, E value, Comparator<? super E> comparator) {
- int len = sortedArray.length;
- for (int i = 0; i < len; i++) {
- if (comparator.compare(value, sortedArray[i]) < 0) {
- return i;
- }
- }
- return len;
- }
-
- /**
- * Return a one-use Iterable for the Iterator given.
- * Throws an IllegalStateException if iterable() is called more than once.
- * As such, this utility should only be used in one-use situations, such as
- * a "for" loop.
- */
- public static <E> Iterable<E> iterable(Iterator<? extends E> iterator) {
- return new SingleUseIterable<E>(iterator);
- }
-
- /**
- * Return an iterable on the elements in the specified array.
- * java.util.Arrays#iterable(Object[] array)
- */
- public static <E> Iterable<E> iterable(E... array) {
- return Arrays.asList(array);
- }
-
- /**
- * Return an iterator on the elements in the specified array.
- * java.util.Arrays#iterator(Object[] array)
- */
- public static <E> Iterator<E> iterator(E... array) {
- return new ArrayIterator<E>(array);
- }
-
- /**
- * Return the index of the last occurrence of the
- * specified element in the specified iterator,
- * or return -1 if there is no such index.
- * java.util.Iterator#lastIndexOf(Object o)
- */
- public static int lastIndexOf(Iterator<?> iterator, Object value) {
- return (iterator.hasNext()) ? list(iterator).lastIndexOf(value) : -1;
- }
-
- /**
- * Return the index of the last occurrence of the
- * specified element in the specified iterator,
- * or return -1 if there is no such index.
- * java.util.Iterator#lastIndexOf(Object o)
- */
- public static int lastIndexOf(Iterator<?> iterator, int size, Object value) {
- return (iterator.hasNext()) ? list(iterator, size).lastIndexOf(value) : -1;
- }
-
- /**
- * Return the index of the last occurrence of the
- * specified element in the specified array,
- * or return -1 if there is no such index.
- * java.util.Arrays#lastIndexOf(Object[] array, Object o)
- */
- public static int lastIndexOf(Object[] array, Object value) {
- int len = array.length;
- if (value == null) {
- for (int i = len; i-- > 0; ) {
- if (array[i] == null) {
- return i;
- }
- }
- } else {
- for (int i = len; i-- > 0; ) {
- if (value.equals(array[i])) {
- return i;
- }
- }
- }
- return -1;
- }
-
- /**
- * Return the index of the last occurrence of the
- * specified element in the specified array,
- * or return -1 if there is no such index.
- * java.util.Arrays#lastIndexOf(char[] array, char value)
- */
- public static int lastIndexOf(char[] array, char value) {
- for (int i = array.length; i-- > 0; ) {
- if (array[i] == value) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Return the index of the last occurrence of the
- * specified element in the specified array,
- * or return -1 if there is no such index.
- * java.util.Arrays#lastIndexOf(int[] array, int value)
- */
- public static int lastIndexOf(int[] array, int value) {
- for (int i = array.length; i-- > 0; ) {
- if (array[i] == value) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Return a list corresponding to the specified iterable.
- * java.lang.Iterable#toList()
- */
- public static <E> ArrayList<E> list(Iterable<? extends E> iterable) {
- return list(iterable.iterator());
- }
-
- /**
- * Return a list corresponding to the specified iterable.
- * java.lang.Iterable#toList()
- */
- public static <E> ArrayList<E> list(Iterable<? extends E> iterable, int size) {
- return list(iterable.iterator(), size);
- }
-
- /**
- * Return a list corresponding to the specified iterator.
- * java.util.Iterator#toList()
- */
- public static <E> ArrayList<E> list(Iterator<? extends E> iterator) {
- return list(iterator, new ArrayList<E>());
- }
-
- /**
- * Return a list corresponding to the specified iterator.
- * java.util.Iterator#toList()
- */
- public static <E> ArrayList<E> list(Iterator<? extends E> iterator, int size) {
- return list(iterator, new ArrayList<E>(size));
- }
-
- private static <E> ArrayList<E> list(Iterator<? extends E> iterator, ArrayList<E> list) {
- while (iterator.hasNext()) {
- list.add(iterator.next());
- }
- return list;
- }
-
- /**
- * Return a list corresponding to the specified array.
- * Unlike java.util.Arrays.asList(Object[]), the list
- * is modifiable and is not backed by the array.
- */
- public static <E> ArrayList<E> list(E... array) {
- ArrayList<E> list = new ArrayList<E>(array.length);
- for (E item : array) {
- list.add(item);
- }
- return list;
- }
-
- /**
- * Return a list iterator for the specified array.
- * java.util.Arrays#listIterator(Object[] array)
- */
- public static <E> ListIterator<E> listIterator(E... array) {
- return listIterator(array, 0);
- }
-
- /**
- * Return a list iterator for the specified array
- * starting at the specified position in the array.
- * java.util.Arrays#listIterator(Object[] array, int index)
- */
- public static <E> ListIterator<E> listIterator(E[] array, int index) {
- return Arrays.asList(array).listIterator(index);
- }
-
- /**
- * Return the character from the specified array with the maximum value.
- * java.util.Arrays#max(char[] array)
- */
- public static char max(char... array) {
- int len = array.length;
- if (len == 0) {
- throw new IndexOutOfBoundsException();
- }
- char max = array[0];
- // start at 1
- for (int i = 1; i < len; i++) {
- char next = array[i];
- if (next > max) {
- max = next;
- }
- }
- return max;
- }
-
- /**
- * Return the integer from the specified array with the maximum value.
- * java.util.Arrays#max(int[] array)
- */
- public static int max(int... array) {
- int len = array.length;
- if (len == 0) {
- throw new IndexOutOfBoundsException();
- }
- int max = array[0];
- // start at 1
- for (int i = 1; i < len; i++) {
- int next = array[i];
- if (next > max) {
- max = next;
- }
- }
- return max;
- }
-
- /**
- * Return the character from the specified array with the minimum value.
- * java.util.Arrays#min(char[] array)
- */
- public static char min(char... array) {
- int len = array.length;
- if (len == 0) {
- throw new IndexOutOfBoundsException();
- }
- char min = array[0];
- // start at 1
- for (int i = 1; i < len; i++) {
- char next = array[i];
- if (next < min) {
- min = next;
- }
- }
- return min;
- }
-
- /**
- * Return the integer from the specified array with the minimum value.
- * java.util.Arrays#min(int[] array)
- */
- public static int min(int... array) {
- int len = array.length;
- if (len == 0) {
- throw new IndexOutOfBoundsException();
- }
- int min = array[0];
- // start at 1
- for (int i = 1; i < len; i++) {
- int next = array[i];
- if (next < min) {
- min = next;
- }
- }
- return min;
- }
-
- /**
- * Move an element from the specified source index to the specified target
- * index. Return the altered array.
- * java.util.Arrays#move(Object[] array, int targetIndex, int sourceIndex)
- */
- public static <E> E[] move(E[] array, int targetIndex, int sourceIndex) {
- return (targetIndex == sourceIndex) ? array : move_(array, targetIndex, sourceIndex);
- }
-
- /**
- * assume targetIndex != sourceIndex
- */
- private static <E> E[] move_(E[] array, int targetIndex, int sourceIndex) {
- E temp = array[sourceIndex];
- if (targetIndex < sourceIndex) {
- System.arraycopy(array, targetIndex, array, targetIndex + 1, sourceIndex - targetIndex);
- } else {
- System.arraycopy(array, sourceIndex + 1, array, sourceIndex, targetIndex - sourceIndex);
- }
- array[targetIndex] = temp;
- return array;
- }
-
- /**
- * Move elements from the specified source index to the specified target
- * index. Return the altered array.
- * java.util.Arrays#move(Object[] array, int targetIndex, int sourceIndex, int length)
- */
- public static <E> E[] move(E[] array, int targetIndex, int sourceIndex, int length) {
- if ((targetIndex == sourceIndex) || (length == 0)) {
- return array;
- }
- if (length == 1) {
- return move_(array, targetIndex, sourceIndex);
- }
- E[] temp = newArray(array, length);
- System.arraycopy(array, sourceIndex, temp, 0, length);
- if (targetIndex < sourceIndex) {
- System.arraycopy(array, targetIndex, array, targetIndex + length, sourceIndex - targetIndex);
- } else {
- System.arraycopy(array, sourceIndex + length, array, sourceIndex, targetIndex - sourceIndex);
- }
- System.arraycopy(temp, 0, array, targetIndex, length);
- return array;
- }
-
- /**
- * Move an element from the specified source index to the specified target
- * index. Return the altered array.
- * java.util.Arrays#move(int[] array, int targetIndex, int sourceIndex)
- */
- public static int[] move(int[] array, int targetIndex, int sourceIndex) {
- return (targetIndex == sourceIndex) ? array : move_(array, targetIndex, sourceIndex);
- }
-
- /**
- * assume targetIndex != sourceIndex
- */
- private static int[] move_(int[] array, int targetIndex, int sourceIndex) {
- int temp = array[sourceIndex];
- if (targetIndex < sourceIndex) {
- System.arraycopy(array, targetIndex, array, targetIndex + 1, sourceIndex - targetIndex);
- } else {
- System.arraycopy(array, sourceIndex + 1, array, sourceIndex, targetIndex - sourceIndex);
- }
- array[targetIndex] = temp;
- return array;
- }
-
- /**
- * Move elements from the specified source index to the specified target
- * index. Return the altered array.
- * java.util.Arrays#move(int[] array, int targetIndex, int sourceIndex, int length)
- */
- public static int[] move(int[] array, int targetIndex, int sourceIndex, int length) {
- if ((targetIndex == sourceIndex) || (length == 0)) {
- return array;
- }
- if (length == 1) {
- return move_(array, targetIndex, sourceIndex);
- }
- int[] temp = new int[length];
- System.arraycopy(array, sourceIndex, temp, 0, length);
- if (targetIndex < sourceIndex) {
- System.arraycopy(array, targetIndex, array, targetIndex + length, sourceIndex - targetIndex);
- } else {
- System.arraycopy(array, sourceIndex + length, array, sourceIndex, targetIndex - sourceIndex);
- }
- System.arraycopy(temp, 0, array, targetIndex, length);
- return array;
- }
-
- /**
- * Move an element from the specified source index to the specified target
- * index. Return the altered array.
- * java.util.Arrays#move(char[] array, int targetIndex, int sourceIndex)
- */
- public static char[] move(char[] array, int targetIndex, int sourceIndex) {
- return (targetIndex == sourceIndex) ? array : move_(array, targetIndex, sourceIndex);
- }
-
- /**
- * assume targetIndex != sourceIndex
- */
- private static char[] move_(char[] array, int targetIndex, int sourceIndex) {
- char temp = array[sourceIndex];
- if (targetIndex < sourceIndex) {
- System.arraycopy(array, targetIndex, array, targetIndex + 1, sourceIndex - targetIndex);
- } else {
- System.arraycopy(array, sourceIndex + 1, array, sourceIndex, targetIndex - sourceIndex);
- }
- array[targetIndex] = temp;
- return array;
- }
-
- /**
- * Move elements from the specified source index to the specified target
- * index. Return the altered array.
- * java.util.Arrays#move(char[] array, int targetIndex, int sourceIndex, int length)
- */
- public static char[] move(char[] array, int targetIndex, int sourceIndex, int length) {
- if ((targetIndex == sourceIndex) || (length == 0)) {
- return array;
- }
- if (length == 1) {
- return move_(array, targetIndex, sourceIndex);
- }
- char[] temp = new char[length];
- System.arraycopy(array, sourceIndex, temp, 0, length);
- if (targetIndex < sourceIndex) {
- System.arraycopy(array, targetIndex, array, targetIndex + length, sourceIndex - targetIndex);
- } else {
- System.arraycopy(array, sourceIndex + length, array, sourceIndex, targetIndex - sourceIndex);
- }
- System.arraycopy(temp, 0, array, targetIndex, length);
- return array;
- }
-
- /**
- * Move an element from the specified source index to the specified target
- * index. Return the altered list.
- * java.util.List#move(int targetIndex, int sourceIndex)
- */
- public static <E> List<E> move(List<E> list, int targetIndex, int sourceIndex) {
- return (targetIndex == sourceIndex) ? list : move_(list, targetIndex, sourceIndex);
- }
-
- /**
- * assume targetIndex != sourceIndex
- */
- private static <E> List<E> move_(List<E> list, int targetIndex, int sourceIndex) {
- if (list instanceof RandomAccess) {
- // move elements, leaving the list in place
- E temp = list.get(sourceIndex);
- if (targetIndex < sourceIndex) {
- for (int i = sourceIndex; i-- > targetIndex; ) {
- list.set(i + 1, list.get(i));
- }
- } else {
- for (int i = sourceIndex; i < targetIndex; i++) {
- list.set(i, list.get(i + 1));
- }
- }
- list.set(targetIndex, temp);
- } else {
- // remove the element and re-add it at the target index
- list.add(targetIndex, list.remove(sourceIndex));
- }
- return list;
- }
-
- /**
- * Move elements from the specified source index to the specified target
- * index. Return the altered list.
- * java.util.List#move(int targetIndex, int sourceIndex, int length)
- */
- public static <E> List<E> move(List<E> list, int targetIndex, int sourceIndex, int length) {
- if ((targetIndex == sourceIndex) || (length == 0)) {
- return list;
- }
- if (length == 1) {
- return move_(list, targetIndex, sourceIndex);
- }
- if (list instanceof RandomAccess) {
- // move elements, leaving the list in place
- ArrayList<E> temp = new ArrayList<E>(list.subList(sourceIndex, sourceIndex + length));
- if (targetIndex < sourceIndex) {
- for (int i = sourceIndex; i-- > targetIndex; ) {
- list.set(i + length, list.get(i));
- }
- } else {
- for (int i = sourceIndex; i < targetIndex; i++) {
- list.set(i, list.get(i + length));
- }
- }
- for (int i = 0; i < length; i++) {
- list.set(targetIndex + i, temp.get(i));
- }
- } else {
- // remove the elements and re-add them at the target index
- list.addAll(targetIndex, removeElementsAtIndex(list, sourceIndex, length));
- }
- return list;
- }
-
- /**
- * Replace all occurrences of the specified old value with
- * the specified new value.
- * java.util.Arrays#replaceAll(Object[] array, Object oldValue, Object newValue)
- */
- public static <E> E[] replaceAll(E[] array, Object oldValue, E newValue) {
- if (oldValue == null) {
- for (int i = array.length; i-- > 0; ) {
- if (array[i] == null) {
- array[i] = newValue;
- }
- }
- } else {
- for (int i = array.length; i-- > 0; ) {
- if (oldValue.equals(array[i])) {
- array[i] = newValue;
- }
- }
- }
- return array;
- }
-
- /**
- * Replace all occurrences of the specified old value with
- * the specified new value.
- * java.util.Arrays#replaceAll(int[] array, int oldValue, int newValue)
- */
- public static int[] replaceAll(int[] array, int oldValue, int newValue) {
- for (int i = array.length; i-- > 0; ) {
- if (array[i] == oldValue) {
- array[i] = newValue;
- }
- }
- return array;
- }
-
- /**
- * Replace all occurrences of the specified old value with
- * the specified new value.
- * java.util.Arrays#replaceAll(char[] array, char oldValue, char newValue)
- */
- public static char[] replaceAll(char[] array, char oldValue, char newValue) {
- for (int i = array.length; i-- > 0; ) {
- if (array[i] == oldValue) {
- array[i] = newValue;
- }
- }
- return array;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified element removed.
- * java.util.Arrays#remove(Object[] array, Object value)
- */
- public static <E> E[] remove(E[] array, Object value) {
- return removeElementAtIndex(array, indexOf(array, value));
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified element removed.
- * java.util.Arrays#remove(char[] array, char value)
- */
- public static char[] remove(char[] array, char value) {
- return removeElementAtIndex(array, indexOf(array, value));
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified element removed.
- * java.util.Arrays#remove(int[] array, int value)
- */
- public static int[] remove(int[] array, int value) {
- return removeElementAtIndex(array, indexOf(array, value));
- }
-
- /**
- * Remove all the elements returned by the specified iterable
- * from the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#removeAll(java.lang.Iterable iterable)
- */
- public static boolean removeAll(Collection<?> collection, Iterable<?> iterable) {
- return removeAll(collection, iterable.iterator());
- }
-
- /**
- * Remove all the elements returned by the specified iterable
- * from the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#removeAll(java.lang.Iterable iterable)
- */
- public static boolean removeAll(Collection<?> collection, Iterable<?> iterable, int size) {
- return removeAll(collection, iterable.iterator(), size);
- }
-
- /**
- * Remove all the elements returned by the specified iterator
- * from the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#removeAll(java.util.Iterator iterator)
- */
- public static boolean removeAll(Collection<?> collection, Iterator<?> iterator) {
- return (iterator.hasNext()) ? collection.removeAll(set(iterator)) : false;
- }
-
- /**
- * Remove all the elements returned by the specified iterator
- * from the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#removeAll(java.util.Iterator iterator)
- */
- public static boolean removeAll(Collection<?> collection, Iterator<?> iterator, int size) {
- return (iterator.hasNext()) ? collection.removeAll(set(iterator, size)) : false;
- }
-
- /**
- * Remove all the elements in the specified array
- * from the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#removeAll(Object[] array)
- */
- public static boolean removeAll(Collection<?> collection, Object[] array) {
- return collection.removeAll(set(array));
- }
-
- /**
- * Remove from the specified array all the elements in
- * the specified iterable and return the result.
- * java.util.Arrays#removeAll(Object[] array, Iterable iterable)
- */
- public static <E> E[] removeAll(E[] array, Iterable<?> iterable) {
- return removeAll(array, iterable.iterator());
- }
-
- /**
- * Remove from the specified array all the elements in
- * the specified iterable and return the result.
- * java.util.Arrays#removeAll(Object[] array, Iterable iterable)
- */
- public static <E> E[] removeAll(E[] array, Iterable<?> iterable, int size) {
- return removeAll(array, iterable.iterator(), size);
- }
-
- /**
- * Remove from the specified array all the elements in
- * the specified iterator and return the result.
- * java.util.Arrays#removeAll(Object[] array, Iterator iterator)
- */
- public static <E> E[] removeAll(E[] array, Iterator<?> iterator) {
- return (iterator.hasNext()) ? removeAll_(array, set(iterator)) : array;
- }
-
- /**
- * Remove from the specified array all the elements in
- * the specified iterator and return the result.
- * java.util.Arrays#removeAll(Object[] array, Iterator iterator)
- */
- public static <E> E[] removeAll(E[] array, Iterator<?> iterator, int size) {
- return (iterator.hasNext()) ? removeAll_(array, set(iterator, size)) : array;
- }
-
- /**
- * Remove from the specified array all the elements in
- * the specified collection and return the result.
- * java.util.Arrays#removeAll(Object[] array, Collection collection)
- */
- public static <E> E[] removeAll(E[] array, Collection<?> collection) {
- return (collection.isEmpty()) ? array : removeAll_(array, collection);
- }
-
- /**
- * assume the collection is non-empty
- */
- private static <E> E[] removeAll_(E[] array, Collection<?> collection) {
- int arrayLength = array.length;
- return (arrayLength == 0) ? array : removeAll(array, collection, arrayLength);
- }
-
- /**
- * assume the collection is non-empty and arrayLength > 0
- */
- private static <E> E[] removeAll(E[] array, Collection<?> collection, int arrayLength) {
- int[] indices = new int[arrayLength];
- int j = 0;
- for (int i = 0; i < arrayLength; i++) {
- if ( ! collection.contains(array[i])) {
- indices[j++] = i;
- }
- }
- if (j == arrayLength) {
- return array; // nothing was removed
- }
- E[] result = newArray(array, j);
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove from the first specified array all the elements in
- * the second specified array and return the result.
- * java.util.Arrays#removeAll(Object[] array1, Object[] array2)
- */
- public static <E> E[] removeAll(E[] array1, Object[] array2) {
- // convert to a bag to take advantage of hashed look-up
- return (array2.length == 0) ? array1 : removeAll_(array1, set(array2));
- }
-
- /**
- * Remove from the first specified array all the elements in
- * the second specified array and return the result.
- * java.util.Arrays#removeAll(char[] array1, char[] array2)
- */
- public static char[] removeAll(char[] array1, char[] array2) {
- if (array2.length == 0) {
- return array1;
- }
- int array1Length = array1.length;
- if (array1Length == 0) {
- return array1;
- }
- int[] indices = new int[array1Length];
- int j = 0;
- for (int i = 0; i < array1Length; i++) {
- if ( ! contains(array2, array1[i])) {
- indices[j++] = i;
- }
- }
- if (j == array1Length) {
- return array1; // nothing was removed
- }
- char[] result = new char[j];
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array1[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove from the first specified array all the elements in
- * the second specified array and return the result.
- * java.util.Arrays#removeAll(int[] array1, int[] array2)
- */
- public static int[] removeAll(int[] array1, int[] array2) {
- if (array2.length == 0) {
- return array1;
- }
- int array1Length = array1.length;
- if (array1Length == 0) {
- return array1;
- }
- int[] indices = new int[array1Length];
- int j = 0;
- for (int i = 0; i < array1Length; i++) {
- if ( ! contains(array2, array1[i])) {
- indices[j++] = i;
- }
- }
- if (j == array1Length) {
- return array1; // nothing was removed
- }
- int[] result = new int[j];
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array1[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove all occurrences of the specified element
- * from the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#removeAllOccurrences(Object value)
- */
- public static boolean removeAllOccurrences(Collection<?> collection, Object value) {
- boolean modified = false;
- Iterator<?> stream = collection.iterator();
- if (value == null) {
- while (stream.hasNext()) {
- if (stream.next() == null) {
- stream.remove();
- modified = true;
- }
- }
- } else {
- while (stream.hasNext()) {
- if (value.equals(stream.next())) {
- stream.remove();
- modified = true;
- }
- }
- }
- return modified;
- }
-
- /**
- * Remove from the specified array all occurrences of
- * the specified element and return the result.
- * java.util.Arrays#removeAllOccurrences(Object[] array, Object value)
- */
- public static <E> E[] removeAllOccurrences(E[] array, Object value) {
- int arrayLength = array.length;
- if (arrayLength == 0) {
- return array;
- }
- int[] indices = new int[arrayLength];
- int j = 0;
- if (value == null) {
- for (int i = arrayLength; i-- > 0; ) {
- if (array[i] != null) {
- indices[j++] = i;
- }
- }
- } else {
- for (int i = array.length; i-- > 0; ) {
- if ( ! value.equals(array[i])) {
- indices[j++] = i;
- }
- }
- }
- if (j == arrayLength) {
- return array; // nothing was removed
- }
- E[] result = newArray(array, j);
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove from the specified array all occurrences of
- * the specified element and return the result.
- * java.util.Arrays#removeAllOccurrences(char[] array, char value)
- */
- public static char[] removeAllOccurrences(char[] array, char value) {
- int arrayLength = array.length;
- if (arrayLength == 0) {
- return array;
- }
- int[] indices = new int[arrayLength];
- int j = 0;
- for (int i = arrayLength; i-- > 0; ) {
- if (array[i] != value) {
- indices[j++] = i;
- }
- }
- if (j == arrayLength) {
- return array; // nothing was removed
- }
- char[] result = new char[j];
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove from the specified array all occurrences of
- * the specified element and return the result.
- * java.util.Arrays#removeAllOccurrences(int[] array, int value)
- */
- public static int[] removeAllOccurrences(int[] array, int value) {
- int arrayLength = array.length;
- if (arrayLength == 0) {
- return array;
- }
- int[] indices = new int[arrayLength];
- int j = 0;
- for (int i = arrayLength; i-- > 0; ) {
- if (array[i] != value) {
- indices[j++] = i;
- }
- }
- if (j == arrayLength) {
- return array; // nothing was removed
- }
- int[] result = new int[j];
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array[indices[i]];
- }
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified element removed.
- * java.util.Arrays#removeElementAtIndex(Object[] array, int index)
- */
- public static <E> E[] removeElementAtIndex(E[] array, int index) {
- return removeElementsAtIndex(array, index, 1);
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified element removed.
- * java.util.Arrays#removeElementAtIndex(char[] array, int index)
- */
- public static char[] removeElementAtIndex(char[] array, int index) {
- return removeElementsAtIndex(array, index, 1);
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified element removed.
- * java.util.Arrays#removeElementAtIndex(int[] array, int index)
- */
- public static int[] removeElementAtIndex(int[] array, int index) {
- return removeElementsAtIndex(array, index, 1);
- }
-
- /**
- * Remove the elements at the specified index.
- * Return the removed elements.
- * java.util.List#remove(int index, int length)
- */
- public static <E> ArrayList<E> removeElementsAtIndex(List<E> list, int index, int length) {
- List<E> subList = list.subList(index, index + length);
- ArrayList<E> result = new ArrayList<E>(subList);
- subList.clear();
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified elements removed.
- * java.util.Arrays#removeElementsAtIndex(Object[] array, int index, int length)
- */
- public static <E> E[] removeElementsAtIndex(E[] array, int index, int length) {
- int arrayLength = array.length;
- int newLength = arrayLength - length;
- E[] result = newArray(array, newLength);
- if ((newLength == 0) && (index == 0)) {
- return result; // performance tweak
- }
- System.arraycopy(array, 0, result, 0, index);
- System.arraycopy(array, index + length, result, index, newLength - index);
- return result;
- }
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified elements removed.
- * java.util.Arrays#removeElementAtIndex(char[] array, int index, int length)
- */
- public static char[] removeElementsAtIndex(char[] array, int index, int length) {
- int arrayLength = array.length;
- int newLength = arrayLength - length;
- if ((newLength == 0) && (index == 0)) {
- return EMPTY_CHAR_ARRAY; // performance tweak
- }
- char[] result = new char[newLength];
- System.arraycopy(array, 0, result, 0, index);
- System.arraycopy(array, index + length, result, index, newLength - index);
- return result;
- }
- private static final char[] EMPTY_CHAR_ARRAY = new char[0];
-
- /**
- * Return a new array that contains the elements in the
- * specified array with the specified elements removed.
- * java.util.Arrays#removeElementAtIndex(int[] array, int index, int length)
- */
- public static int[] removeElementsAtIndex(int[] array, int index, int length) {
- int arrayLength = array.length;
- int newLength = arrayLength - length;
- if ((newLength == 0) && (index == 0)) {
- return EMPTY_INT_ARRAY; // performance tweak
- }
- int[] result = new int[newLength];
- System.arraycopy(array, 0, result, 0, index);
- System.arraycopy(array, index + length, result, index, newLength - index);
- return result;
- }
- private static final int[] EMPTY_INT_ARRAY = new int[0];
-
- /**
- * Remove any duplicate elements from the specified array,
- * while maintaining the order.
- */
- public static <E> E[] removeDuplicateElements(E... array) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- ArrayList<E> temp = list(array);
- return removeDuplicateElements(temp, len) ?
- temp.toArray(newArray(array, temp.size()))
- :
- array;
- }
-
- /**
- * Remove any duplicate elements from the specified list,
- * while maintaining the order.
- * Return whether the list changed as a result.
- */
- public static <E> boolean removeDuplicateElements(List<E> list) {
- int size = list.size();
- if ((size == 0) || (size == 1)) {
- return false;
- }
- return removeDuplicateElements(list, size);
- }
-
- /**
- * assume list is non-empty
- */
- private static <E> boolean removeDuplicateElements(List<E> list, int size) {
- LinkedHashSet<E> temp = new LinkedHashSet<E>(size); // take advantage of hashed look-up
- boolean changed = false;
- for (E item : list) {
- if ( ! temp.add(item)) {
- changed = true; // duplicate item
- }
- }
- if (changed) {
- int i = 0;
- for (Iterator<E> stream = temp.iterator(); stream.hasNext(); ) {
- list.set(i, stream.next());
- i++;
- }
- int tempSize = temp.size();
- for (i = list.size(); i-- > tempSize; ) {
- list.remove(i); // pull off the end
- }
- }
- return changed;
- }
-
- /**
- * Retain only the elements in the specified iterable
- * in the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#retainAll(java.lang.Iterable iterable)
- */
- public static boolean retainAll(Collection<?> collection, Iterable<?> iterable) {
- return retainAll(collection, iterable.iterator());
- }
-
- /**
- * Retain only the elements in the specified iterable
- * in the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#retainAll(java.lang.Iterable iterable)
- */
- public static boolean retainAll(Collection<?> collection, Iterable<?> iterable, int size) {
- return retainAll(collection, iterable.iterator(), size);
- }
-
- /**
- * Retain only the elements in the specified iterator
- * in the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#retainAll(java.util.Iterator iterator)
- */
- public static boolean retainAll(Collection<?> collection, Iterator<?> iterator) {
- if (iterator.hasNext()) {
- return collection.retainAll(set(iterator));
- }
- if (collection.isEmpty()) {
- return false;
- }
- collection.clear();
- return true;
- }
-
- /**
- * Retain only the elements in the specified iterator
- * in the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#retainAll(java.util.Iterator iterator)
- */
- public static boolean retainAll(Collection<?> collection, Iterator<?> iterator, int size) {
- if (iterator.hasNext()) {
- return collection.retainAll(set(iterator, size));
- }
- if (collection.isEmpty()) {
- return false;
- }
- collection.clear();
- return true;
- }
-
- /**
- * Retain only the elements in the specified array
- * in the specified collection.
- * Return whether the collection changed as a result.
- * java.util.Collection#retainAll(Object[] array)
- */
- public static boolean retainAll(Collection<?> collection, Object[] array) {
- if (array.length > 0) {
- return collection.retainAll(set(array));
- }
- if (collection.isEmpty()) {
- return false;
- }
- collection.clear();
- return true;
- }
-
- /**
- * Retain in the specified array all the elements in
- * the specified iterable and return the result.
- * java.util.Arrays#retainAll(Object[] array, Iterable iterable)
- */
- public static <E> E[] retainAll(E[] array, Iterable<?> iterable) {
- int arrayLength = array.length;
- return (arrayLength == 0) ? array : retainAll(array, arrayLength, iterable.iterator());
- }
-
- /**
- * Retain in the specified array all the elements in
- * the specified iterable and return the result.
- * java.util.Arrays#retainAll(Object[] array, Iterable iterable)
- */
- public static <E> E[] retainAll(E[] array, Iterable<?> iterable, int size) {
- int arrayLength = array.length;
- return (arrayLength == 0) ? array : retainAll(array, arrayLength, iterable.iterator(), size);
- }
-
- /**
- * Retain in the specified array all the elements in
- * the specified iterator and return the result.
- * java.util.Arrays#retainAll(Object[] array, Iterator iterator)
- */
- public static <E> E[] retainAll(E[] array, Iterator<?> iterator) {
- int arrayLength = array.length;
- return (arrayLength == 0) ? array : retainAll(array, arrayLength, iterator);
- }
-
- /**
- * Retain in the specified array all the elements in
- * the specified iterator and return the result.
- * java.util.Arrays#retainAll(Object[] array, Iterator iterator)
- */
- public static <E> E[] retainAll(E[] array, Iterator<?> iterator, int size) {
- int arrayLength = array.length;
- return (arrayLength == 0) ? array : retainAll(array, arrayLength, iterator, size);
- }
-
- /**
- * assume arrayLength > 0
- */
- private static <E> E[] retainAll(E[] array, int arrayLength, Iterator<?> iterator) {
- return (iterator.hasNext()) ?
- retainAll_(array, set(iterator), arrayLength)
- :
- newArray(array, 0);
- }
-
- /**
- * assume arrayLength > 0
- */
- private static <E> E[] retainAll(E[] array, int arrayLength, Iterator<?> iterator, int iteratorSize) {
- return (iterator.hasNext()) ?
- retainAll_(array, set(iterator, iteratorSize), arrayLength)
- :
- newArray(array, 0);
- }
-
- /**
- * Retain in the specified array all the elements in
- * the specified collection and return the result.
- * java.util.Arrays#retainAll(Object[] array, Collection collection)
- */
- public static <E> E[] retainAll(E[] array, Collection<?> collection) {
- int arrayLength = array.length;
- return (arrayLength == 0) ? array : retainAll(array, collection, arrayLength);
- }
-
- /**
- * assume arrayLength > 0
- */
- private static <E> E[] retainAll(E[] array, Collection<?> collection, int arrayLength) {
- return (collection.isEmpty()) ?
- newArray(array, 0)
- :
- retainAll_(array, collection, arrayLength);
- }
-
- /**
- * assume collection is non-empty and arrayLength > 0
- */
- private static <E> E[] retainAll_(E[] array, Collection<?> collection, int arrayLength) {
- int[] indices = new int[arrayLength];
- int j = 0;
- for (int i = 0; i < arrayLength; i++) {
- if (collection.contains(array[i])) {
- indices[j++] = i;
- }
- }
- if (j == arrayLength) {
- return array; // everything was retained
- }
- E[] result = newArray(array, j);
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove from the first specified array all the elements in
- * the second specified array and return the result.
- * java.util.Arrays#retainAll(Object[] array1, Object[] array2)
- */
- public static <E> E[] retainAll(E[] array1, Object[] array2) {
- int array1Length = array1.length;
- return (array2.length == 0) ?
- (array1Length == 0) ? array1 : newArray(array1, 0)
- :
- retainAll(array1, set(array2), array1Length);
- }
-
- /**
- * Remove from the first specified array all the elements in
- * the second specified array and return the result.
- * java.util.Arrays#retainAll(char[] array1, char[] array2)
- */
- public static char[] retainAll(char[] array1, char[] array2) {
- int array1Length = array1.length;
- return (array1Length == 0) ? array1 : retainAll(array1, array2, array1Length);
- }
-
- /**
- * assume array1Length > 0
- */
- private static char[] retainAll(char[] array1, char[] array2, int array1Length) {
- int array2Length = array2.length;
- return (array2Length == 0) ? EMPTY_CHAR_ARRAY : retainAll(array1, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static char[] retainAll(char[] array1, char[] array2, int array1Length, int array2Length) {
- int[] indices = new int[array1Length];
- int j = 0;
- for (int i = 0; i < array1Length; i++) {
- if (contains(array2, array1[i], array2Length)) {
- indices[j++] = i;
- }
- }
- if (j == array1Length) {
- return array1; // everything was retained
- }
- char[] result = new char[j];
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array1[indices[i]];
- }
- return result;
- }
-
- /**
- * Remove from the first specified array all the elements in
- * the second specified array and return the result.
- * java.util.Arrays#retainAll(int[] array1, int[] array2)
- */
- public static int[] retainAll(int[] array1, int[] array2) {
- int array1Length = array1.length;
- return (array1Length == 0) ? array1 : retainAll(array1, array2, array1Length);
- }
-
- /**
- * assume array1Length > 0
- */
- private static int[] retainAll(int[] array1, int[] array2, int array1Length) {
- int array2Length = array2.length;
- return (array2Length == 0) ? EMPTY_INT_ARRAY : retainAll(array1, array2, array1Length, array2Length);
- }
-
- /**
- * assume array1Length > 0 and array2Length > 0
- */
- private static int[] retainAll(int[] array1, int[] array2, int array1Length, int array2Length) {
- int[] indices = new int[array1Length];
- int j = 0;
- for (int i = 0; i < array1Length; i++) {
- if (contains(array2, array1[i], array2Length)) {
- indices[j++] = i;
- }
- }
- if (j == array1Length) {
- return array1; // everything was retained
- }
- int[] result = new int[j];
- int resultLength = result.length;
- for (int i = 0; i < resultLength; i++) {
- result[i] = array1[indices[i]];
- }
- return result;
- }
-
- /**
- * Return the array reversed.
- * java.util.Arrays.reverse(Object[] array)
- */
- public static <E> E[] reverse(E... array) {
- int len = array.length;
- for (int i = 0, mid = len >> 1, j = len - 1; i < mid; i++, j--) {
- swap(array, i, j);
- }
- return array;
- }
-
- /**
- * Return the array reversed.
- * java.util.Arrays.reverse(char[] array)
- */
- public static char[] reverse(char... array) {
- int len = array.length;
- for (int i = 0, mid = len >> 1, j = len - 1; i < mid; i++, j--) {
- swap(array, i, j);
- }
- return array;
- }
-
- /**
- * Return the array reversed.
- * java.util.Arrays.reverse(int[] array)
- */
- public static int[] reverse(int... array) {
- int len = array.length;
- for (int i = 0, mid = len >> 1, j = len - 1; i < mid; i++, j--) {
- swap(array, i, j);
- }
- return array;
- }
-
- /**
- * Return a list with entries in reverse order from those
- * returned by the specified iterable.
- */
- public static <E> List<E> reverseList(Iterable<? extends E> iterable) {
- return reverse(list(iterable));
- }
-
- /**
- * Return a list with entries in reverse order from those
- * returned by the specified iterable.
- */
- public static <E> List<E> reverseList(Iterable<? extends E> iterable, int size) {
- return reverse(list(iterable, size));
- }
-
- /**
- * Return a list with entries in reverse order from those
- * returned by the specified iterator.
- */
- public static <E> List<E> reverseList(Iterator<? extends E> iterator) {
- return reverse(list(iterator));
- }
-
- /**
- * Return a list with entries in reverse order from those
- * returned by the specified iterator.
- */
- public static <E> List<E> reverseList(Iterator<? extends E> iterator, int size) {
- return reverse(list(iterator, size));
- }
-
- /**
- * Return the rotated array after rotating it one position.
- * java.util.Arrays.rotate(Object[] array)
- */
- public static <E> E[] rotate(E... array) {
- return rotate(array, 1);
- }
-
- /**
- * Return the rotated array after rotating it the specified distance.
- * java.util.Arrays.rotate(Object[] array, int distance)
- */
- public static <E> E[] rotate(E[] array, int distance) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- distance = distance % len;
- if (distance < 0) {
- distance += len;
- }
- if (distance == 0) {
- return array;
- }
- for (int cycleStart = 0, nMoved = 0; nMoved != len; cycleStart++) {
- E displaced = array[cycleStart];
- int i = cycleStart;
- do {
- i += distance;
- if (i >= len) {
- i -= len;
- }
- E temp = array[i];
- array[i] = displaced;
- displaced = temp;
- nMoved ++;
- } while (i != cycleStart);
- }
- return array;
- }
-
- /**
- * Return the rotated array after rotating it one position.
- * java.util.Arrays.rotate(char[] array)
- */
- public static char[] rotate(char... array) {
- return rotate(array, 1);
- }
-
- /**
- * Return the rotated array after rotating it the specified distance.
- * java.util.Arrays.rotate(char[] array, int distance)
- */
- public static char[] rotate(char[] array, int distance) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- distance = distance % len;
- if (distance < 0) {
- distance += len;
- }
- if (distance == 0) {
- return array;
- }
- for (int cycleStart = 0, nMoved = 0; nMoved != len; cycleStart++) {
- char displaced = array[cycleStart];
- int i = cycleStart;
- do {
- i += distance;
- if (i >= len) {
- i -= len;
- }
- char temp = array[i];
- array[i] = displaced;
- displaced = temp;
- nMoved ++;
- } while (i != cycleStart);
- }
- return array;
- }
-
- /**
- * Return the rotated array after rotating it one position.
- * java.util.Arrays.rotate(int[] array)
- */
- public static int[] rotate(int... array) {
- return rotate(array, 1);
- }
-
- /**
- * Return the rotated array after rotating it the specified distance.
- * java.util.Arrays.rotate(int[] array, int distance)
- */
- public static int[] rotate(int[] array, int distance) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- distance = distance % len;
- if (distance < 0) {
- distance += len;
- }
- if (distance == 0) {
- return array;
- }
- for (int cycleStart = 0, nMoved = 0; nMoved != len; cycleStart++) {
- int displaced = array[cycleStart];
- int i = cycleStart;
- do {
- i += distance;
- if (i >= len) {
- i -= len;
- }
- int temp = array[i];
- array[i] = displaced;
- displaced = temp;
- nMoved ++;
- } while (i != cycleStart);
- }
- return array;
- }
-
- /**
- * Return a set corresponding to the specified iterable.
- * java.util.HashSet(java.lang.Iterable iterable)
- */
- public static <E> HashSet<E> set(Iterable<? extends E> iterable) {
- return set(iterable.iterator());
- }
-
- /**
- * Return a set corresponding to the specified iterable.
- * java.util.HashSet(java.lang.Iterable iterable)
- */
- public static <E> HashSet<E> set(Iterable<? extends E> iterable, int size) {
- return set(iterable.iterator(), size);
- }
-
- /**
- * Return a set corresponding to the specified iterator.
- * java.util.HashSet(java.util.Iterator iterator)
- */
- public static <E> HashSet<E> set(Iterator<? extends E> iterator) {
- return set(iterator, new HashSet<E>());
- }
-
- /**
- * Return a set corresponding to the specified iterator.
- * java.util.HashSet(java.util.Iterator iterator)
- */
- public static <E> HashSet<E> set(Iterator<? extends E> iterator, int size) {
- return set(iterator, new HashSet<E>(size));
- }
-
- private static <E> HashSet<E> set(Iterator<? extends E> iterator, HashSet<E> set) {
- while (iterator.hasNext()) {
- set.add(iterator.next());
- }
- return set;
- }
-
- /**
- * Return a set corresponding to the specified array.
- * java.util.HashSet(Object[] array)
- */
- public static <E> HashSet<E> set(E... array) {
- HashSet<E> set = new HashSet<E>(array.length);
- for (E item : array) {
- set.add(item);
- }
- return set;
- }
-
- private static final Random RANDOM = new Random();
-
- /**
- * Return the array after "shuffling" it.
- * java.util.Arrays#shuffle(Object[] array)
- */
- public static <E> E[] shuffle(E... array) {
- return shuffle(array, RANDOM);
- }
-
- /**
- * Return the array after "shuffling" it.
- * java.util.Arrays#shuffle(Object[] array, Random r)
- */
- public static <E> E[] shuffle(E[] array, Random random) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- for (int i = len; i-- > 0; ) {
- swap(array, i, random.nextInt(len));
- }
- return array;
- }
-
- /**
- * Return the array after "shuffling" it.
- * java.util.Arrays#shuffle(char[] array)
- */
- public static char[] shuffle(char... array) {
- return shuffle(array, RANDOM);
- }
-
- /**
- * Return the array after "shuffling" it.
- * java.util.Arrays#shuffle(char[] array, Random r)
- */
- public static char[] shuffle(char[] array, Random random) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- for (int i = len; i-- > 0; ) {
- swap(array, i, random.nextInt(len));
- }
- return array;
- }
-
- /**
- * Return the array after "shuffling" it.
- * java.util.Arrays#shuffle(int[] array)
- */
- public static int[] shuffle(int... array) {
- return shuffle(array, RANDOM);
- }
-
- /**
- * Return the array after "shuffling" it.
- * java.util.Arrays#shuffle(int[] array, Random r)
- */
- public static int[] shuffle(int[] array, Random random) {
- int len = array.length;
- if ((len == 0) || (len == 1)) {
- return array;
- }
- for (int i = len; i-- > 0; ) {
- swap(array, i, random.nextInt(len));
- }
- return array;
- }
-
- /**
- * Return an iterator that returns only the single,
- * specified object.
- * Object#toIterator() ?!
- */
- public static <E> Iterator<E> singletonIterator(E value) {
- return new SingleElementIterator<E>(value);
- }
-
- /**
- * Return the number of elements returned by the specified iterable.
- * java.lang.Iterable#size()
- */
- public static int size(Iterable<?> iterable) {
- return size(iterable.iterator());
- }
-
- /**
- * Return the number of elements returned by the specified iterator.
- * java.util.Iterator#size()
- */
- public static int size(Iterator<?> iterator) {
- int size = 0;
- while (iterator.hasNext()) {
- iterator.next();
- size++;
- }
- return size;
- }
-
- /**
- * Return a sorted set corresponding to the specified iterable.
- * java.util.TreeSet(java.lang.Iterable iterable)
- */
- public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterable<? extends E> iterable) {
- return sortedSet(iterable, null);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterable.
- * java.util.TreeSet(java.lang.Iterable iterable)
- */
- public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterable<? extends E> iterable, int size) {
- return sortedSet(iterable, size, null);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterable
- * and comparator.
- * java.util.TreeSet(java.lang.Iterable iterable, java.util.Comparator c)
- */
- public static <E> TreeSet<E> sortedSet(Iterable<? extends E> iterable, Comparator<? super E> comparator) {
- return sortedSet(iterable.iterator(), comparator);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterable
- * and comparator.
- * java.util.TreeSet(java.lang.Iterable iterable, java.util.Comparator c)
- */
- public static <E> TreeSet<E> sortedSet(Iterable<? extends E> iterable, int size, Comparator<? super E> comparator) {
- return sortedSet(iterable.iterator(), size, comparator);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterator.
- * java.util.TreeSet(java.util.Iterator iterator)
- */
- public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterator<? extends E> iterator) {
- return sortedSet(iterator, null);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterator.
- * java.util.TreeSet(java.util.Iterator iterator)
- */
- public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterator<? extends E> iterator, int size) {
- return sortedSet(iterator, size, null);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterator
- * and comparator.
- * java.util.TreeSet(java.util.Iterator iterator, java.util.Comparator c)
- */
- public static <E> TreeSet<E> sortedSet(Iterator<? extends E> iterator, Comparator<? super E> comparator) {
- return sortedSet(list(iterator), comparator);
- }
-
- /**
- * Return a sorted set corresponding to the specified iterator
- * and comparator.
- * java.util.TreeSet(java.util.Iterator iterator, java.util.Comparator c)
- */
- public static <E> TreeSet<E> sortedSet(Iterator<? extends E> iterator, int size, Comparator<? super E> comparator) {
- return sortedSet(list(iterator, size), comparator);
- }
-
- private static <E> TreeSet<E> sortedSet(List<E> list, Comparator<? super E> comparator) {
- TreeSet<E> sortedSet = new TreeSet<E>(comparator);
- sortedSet.addAll(list);
- return sortedSet;
- }
-
- /**
- * Return a sorted set corresponding to the specified array.
- * java.util.TreeSet(Object[] array)
- */
- public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(E... array) {
- return sortedSet(array, null);
- }
-
- /**
- * Return a sorted set corresponding to the specified array
- * and comparator.
- * java.util.TreeSet(Object[] array, java.util.Comparator c)
- */
- public static <E> TreeSet<E> sortedSet(E[] array, Comparator<? super E> comparator) {
- TreeSet<E> sortedSet = new TreeSet<E>(comparator);
- sortedSet.addAll(Arrays.asList(array));
- return sortedSet;
- }
-
- /**
- * Return a sub-array of the specified array, starting at the specified
- * position with the specified length.
- * java.util.Arrays#subArray(E[] array, int start, int length)
- */
- public static <E> E[] subArray(E[] array, int start, int length) {
- E[] result = newArray(array, length);
- if (length > 0) {
- System.arraycopy(array, start, result, 0, length);
- }
- return result;
- }
-
- /**
- * Return a sub-array of the specified array, starting at the specified
- * position with the specified length.
- * java.util.Arrays#subArray(int[] array, int start, int length)
- */
- public static int[] subArray(int[] array, int start, int length) {
- int[] result = new int[length];
- if (length > 0) {
- System.arraycopy(array, start, result, 0, length);
- }
- return result;
- }
-
- /**
- * Return a sub-array of the specified array, starting at the specified
- * position with the specified length.
- * java.util.Arrays#subArray(char[] array, int start, int length)
- */
- public static char[] subArray(char[] array, int start, int length) {
- char[] result = new char[length];
- if (length > 0) {
- System.arraycopy(array, start, result, 0, length);
- }
- return result;
- }
-
- /**
- * Return the array after the specified elements have been "swapped".
- * java.util.Arrays#swap(Object[] array, int i, int j)
- */
- public static <E> E[] swap(E[] array, int i, int j) {
- E temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- return array;
- }
-
- /**
- * Return the array after the specified elements have been "swapped".
- * java.util.Arrays#swap(char[] array, int i, int j)
- */
- public static char[] swap(char[] array, int i, int j) {
- char temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- return array;
- }
-
- /**
- * Return the array after the specified elements have been "swapped".
- * java.util.Arrays#swap(int[] array, int i, int j)
- */
- public static int[] swap(int[] array, int i, int j) {
- int temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- return array;
- }
-
- /**
- * Return a vector corresponding to the specified iterable.
- * This is useful for legacy code that requires a java.util.Vector.
- * java.util.Vector(java.lang.Iterable iterable)
- */
- public static <E> Vector<E> vector(Iterable<? extends E> iterable) {
- return vector(iterable.iterator());
- }
-
- /**
- * Return a vector corresponding to the specified iterable.
- * This is useful for legacy code that requires a java.util.Vector.
- * java.util.Vector(java.lang.Iterable iterable)
- */
- public static <E> Vector<E> vector(Iterable<? extends E> iterable, int size) {
- return vector(iterable.iterator(), size);
- }
-
- /**
- * Return a vector corresponding to the specified iterator.
- * This is useful for legacy code that requires a java.util.Vector.
- * java.util.Vector(java.util.Iterator iterator)
- */
- public static <E> Vector<E> vector(Iterator<? extends E> iterator) {
- return vector(iterator, new Vector<E>());
- }
-
- /**
- * Return a vector corresponding to the specified iterator.
- * This is useful for legacy code that requires a java.util.Vector.
- * java.util.Vector(java.util.Iterator iterator)
- */
- public static <E> Vector<E> vector(Iterator<? extends E> iterator, int size) {
- return vector(iterator, new Vector<E>(size));
- }
-
- private static <E> Vector<E> vector(Iterator<? extends E> iterator, Vector<E> v) {
- while (iterator.hasNext()) {
- v.addElement(iterator.next());
- }
- return v;
- }
-
- /**
- * Return a vector corresponding to the specified array.
- * This is useful for legacy code that requires a java.util.Vector.
- * java.util.Vector(Object[] array)
- */
- public static <E> Vector<E> vector(E... array) {
- Vector<E> v = new Vector<E>(array.length);
- for (E item : array) {
- v.addElement(item);
- }
- return v;
- }
-
-
- // ********** single-use Iterable **********
-
- /**
- * This is a one-time use iterable that can return a single iterator.
- * Once the iterator is returned the iterable is no longer valid.
- * As such, this utility should only be used in one-time use situations,
- * such as a 'for-each' loop.
- */
- public static class SingleUseIterable<E> implements Iterable<E> {
- private Iterator<E> iterator;
-
- public SingleUseIterable(Iterator<? extends E> iterator) {
- super();
- if (iterator == null) {
- throw new NullPointerException();
- }
- this.iterator = new GenericIteratorWrapper<E>(iterator);
- }
-
- public Iterator<E> iterator() {
- if (this.iterator == null) {
- throw new IllegalStateException("This method has already been called."); //$NON-NLS-1$
- }
- Iterator<E> result = this.iterator;
- this.iterator = null;
- return result;
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.iterator);
- }
-
- }
-
-
- // ********** java.util.Collections enhancements **********
-
- /**
- * Return the destination list after the source list has been copied into it.
- * @see java.util.Collections#copy(java.util.List, java.util.List)
- */
- public static <E> List<? super E> copy(List<? super E> dest, List<? extends E> src) {
- Collections.copy(dest, src);
- return dest;
- }
-
- /**
- * Return the list after it has been "filled".
- * @see java.util.Collections#fill(java.util.List, java.lang.Object)
- */
- public static <E> List<? super E> fill(List<? super E> list, E value) {
- Collections.fill(list, value);
- return list;
- }
-
- /**
- * Return the list after it has been "reversed".
- * @see java.util.Collections#reverse(java.util.List)
- */
- public static <E> List<E> reverse(List<E> list) {
- Collections.reverse(list);
- return list;
- }
-
- /**
- * Return the list after it has been "rotated" by one position.
- * @see java.util.Collections#rotate(java.util.List, int)
- */
- public static <E> List<E> rotate(List<E> list) {
- return rotate(list, 1);
- }
-
- /**
- * Return the list after it has been "rotated".
- * @see java.util.Collections#rotate(java.util.List, int)
- */
- public static <E> List<E> rotate(List<E> list, int distance) {
- Collections.rotate(list, distance);
- return list;
- }
-
- /**
- * Return the list after it has been "shuffled".
- * @see java.util.Collections#shuffle(java.util.List)
- */
- public static <E> List<E> shuffle(List<E> list) {
- Collections.shuffle(list);
- return list;
- }
-
- /**
- * Return the list after it has been "shuffled".
- * @see java.util.Collections#shuffle(java.util.List, java.util.Random)
- */
- public static <E> List<E> shuffle(List<E> list, Random random) {
- Collections.shuffle(list, random);
- return list;
- }
-
- /**
- * Return the list after it has been "sorted".
- * @see java.util.Collections#sort(java.util.List)
- */
- public static <E extends Comparable<? super E>> List<E> sort(List<E> list) {
- Collections.sort(list);
- return list;
- }
-
- /**
- * Return the list after it has been "sorted".
- * @see java.util.Collections#sort(java.util.List, java.util.Comparator)
- */
- public static <E> List<E> sort(List<E> list, Comparator<? super E> comparator) {
- Collections.sort(list, comparator);
- return list;
- }
-
- /**
- * Return the iterable after it has been "sorted".
- */
- public static <E extends Comparable<? super E>> Iterable<E> sort(Iterable<E> iterable) {
- return sort(iterable, null);
- }
-
- /**
- * Return the iterable after it has been "sorted".
- */
- public static <E> Iterable<E> sort(Iterable<E> iterable, Comparator<? super E> comparator) {
- return sort(list(iterable), comparator);
- }
-
- /**
- * Return the iterator after it has been "sorted".
- */
- public static <E extends Comparable<? super E>> Iterator<E> sort(Iterator<? extends E> iterator) {
- return sort(iterator, null);
- }
-
- /**
- * Return the iterator after it has been "sorted".
- */
- public static <E> Iterator<E> sort(Iterator<? extends E> iterator, Comparator<? super E> comparator) {
- return sort(list(iterator), comparator).iterator();
- }
-
- /**
- * Return the list after the specified elements have been "swapped".
- * @see java.util.Collections#swap(java.util.List, int, int)
- */
- public static <E> List<E> swap(List<E> list, int i, int j) {
- Collections.swap(list, i, j);
- return list;
- }
-
-
- // ********** java.util.Arrays enhancements **********
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(boolean[], boolean)
- */
- public static boolean[] fill(boolean[] array, boolean value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(boolean[], int, int, boolean)
- */
- public static boolean[] fill(boolean[] array, int fromIndex, int toIndex, boolean value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(byte[], byte)
- */
- public static byte[] fill(byte[] array, byte value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(byte[], int, int, byte)
- */
- public static byte[] fill(byte[] array, int fromIndex, int toIndex, byte value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(char[], char)
- */
- public static char[] fill(char[] array, char value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(char[], int, int, char)
- */
- public static char[] fill(char[] array, int fromIndex, int toIndex, char value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(double[], double)
- */
- public static double[] fill(double[] array, double value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(double[], int, int, double)
- */
- public static double[] fill(double[] array, int fromIndex, int toIndex, double value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(float[], float)
- */
- public static float[] fill(float[] array, float value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(float[], int, int, float)
- */
- public static float[] fill(float[] array, int fromIndex, int toIndex, float value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(int[], int)
- */
- public static int[] fill(int[] array, int value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(int[], int, int, int)
- */
- public static int[] fill(int[] array, int fromIndex, int toIndex, int value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(Object[], Object)
- */
- public static <E> E[] fill(E[] array, E value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(Object[], int, int, Object)
- */
- public static <E> E[] fill(E[] array, int fromIndex, int toIndex, E value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(long[], long)
- */
- public static long[] fill(long[] array, long value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(long[], int, int, long)
- */
- public static long[] fill(long[] array, int fromIndex, int toIndex, long value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(short[], short)
- */
- public static short[] fill(short[] array, short value) {
- Arrays.fill(array, value);
- return array;
- }
-
- /**
- * Return the array after it has been "filled".
- * @see java.util.Arrays#fill(short[], int, int, short)
- */
- public static short[] fill(short[] array, int fromIndex, int toIndex, short value) {
- Arrays.fill(array, fromIndex, toIndex, value);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(byte[])
- */
- public static byte[] sort(byte... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(byte[], int, int)
- */
- public static byte[] sort(byte[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(char[])
- */
- public static char[] sort(char... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(char[], int, int)
- */
- public static char[] sort(char[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(double[])
- */
- public static double[] sort(double... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(double[], int, int)
- */
- public static double[] sort(double[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(float[])
- */
- public static float[] sort(float... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(float[], int, int)
- */
- public static float[] sort(float[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(int[])
- */
- public static int[] sort(int... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(int[], int, int)
- */
- public static int[] sort(int[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(Object[])
- */
- public static <E> E[] sort(E... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(Object[], java.util.Comparator)
- */
- public static <E> E[] sort(E[] array, Comparator<? super E> comparator) {
- Arrays.sort(array, comparator);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(Object[], int, int)
- */
- public static <E> E[] sort(E[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(Object[], int, int, java.util.Comparator)
- */
- public static <E> E[] sort(E[] array, int fromIndex, int toIndex, Comparator<? super E> comparator) {
- Arrays.sort(array, fromIndex, toIndex, comparator);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(long[])
- */
- public static long[] sort(long... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(long[], int, int)
- */
- public static long[] sort(long[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(short[])
- */
- public static short[] sort(short... array) {
- Arrays.sort(array);
- return array;
- }
-
- /**
- * Return the array after it has been "sorted".
- * @see java.util.Arrays#sort(short[], int, int)
- */
- public static short[] sort(short[] array, int fromIndex, int toIndex) {
- Arrays.sort(array, fromIndex, toIndex);
- return array;
- }
-
-
- // ********** constructor **********
-
- /**
- * Suppress default constructor, ensuring non-instantiability.
- */
- private CollectionTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Counter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Counter.java
deleted file mode 100644
index fbe3cde738..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Counter.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-
-/**
- * This class can be used wherever a mutable integer object is needed.
- * It is a cross between an int and an Integer. It can be stored in a standard
- * container (e.g. Collection) but can be modified.
- */
-public final class Counter
- implements Cloneable, Serializable
-{
- private int count = 0;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct a counter with the specified initial value.
- */
- public Counter(int count) {
- super();
- this.count = count;
- }
-
- /**
- * Construct a counter with an initial value of zero.
- */
- public Counter() {
- this(0);
- }
-
- /**
- * Return the current count of the counter.
- */
- public synchronized int count() {
- return this.count;
- }
-
- /**
- * Increment and return the current count of the counter.
- */
- public synchronized int increment() {
- return ++this.count;
- }
-
- /**
- * Increment and return the current count of the counter.
- */
- public synchronized int increment(int increment) {
- return this.count += increment;
- }
-
- /**
- * Derement and return the current count of the counter.
- */
- public synchronized int decrement() {
- return --this.count;
- }
-
- /**
- * Derement and return the current count of the counter.
- */
- public synchronized int decrement(int decrement) {
- return this.count -= decrement;
- }
-
- @Override
- public synchronized boolean equals(Object o) {
- if ( ! (o instanceof Counter)) {
- return false;
- }
- return this.count == ((Counter) o).count;
- }
-
- @Override
- public synchronized int hashCode() {
- return this.count;
- }
-
- @Override
- public synchronized Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- @Override
- public synchronized String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append(ClassTools.shortClassNameForObject(this));
- sb.append('(');
- sb.append(this.count);
- sb.append(')');
- return sb.toString();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/EmptyIterable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/EmptyIterable.java
deleted file mode 100644
index 1f90f3d4f0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/EmptyIterable.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-
-/**
- * An <code>EmptyIterable</code> is just that.
- */
-public final class EmptyIterable<E>
- implements Iterable<E>
-{
-
- // singleton
- @SuppressWarnings("unchecked")
- private static final EmptyIterable INSTANCE = new EmptyIterable();
-
- /**
- * Return the singleton.
- */
- @SuppressWarnings("unchecked")
- public static <T> Iterable<T> instance() {
- return INSTANCE;
- }
-
- /**
- * Ensure single instance.
- */
- private EmptyIterable() {
- super();
- }
-
- public Iterator<E> iterator() {
- return EmptyIterator.instance();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java
deleted file mode 100644
index 44154c4ed5..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/FileTools.java
+++ /dev/null
@@ -1,1006 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
-import org.eclipse.jpt.utility.internal.iterators.CompositeIterator;
-import org.eclipse.jpt.utility.internal.iterators.FilteringIterator;
-import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
-
-/**
- * Assorted file tools:
- * - delete entire trees of directories and files
- * - build iterators on entire trees of directories and files
- * - build a temporary directory
- * - "canonize" files
- */
-public final class FileTools {
-
- public static final String USER_HOME_DIRECTORY_NAME = System.getProperty("user.home");
- public static final String USER_TEMPORARY_DIRECTORY_NAME = System.getProperty("java.io.tmpdir");
- public static String DEFAULT_TEMPORARY_DIRECTORY_NAME = "tmpdir";
- public static final String CURRENT_WORKING_DIRECTORY_NAME = System.getProperty("user.dir");
-
- /** A list of some invalid file name characters.
- : is the filename separator in MacOS and the drive indicator in DOS
- * is a DOS wildcard character
- | is a DOS redirection character
- & is our own escape character
- / is the filename separator in Unix and the command option tag in DOS
- \ is the filename separator in DOS/Windows and the escape character in Unix
- ; is ???
- ? is a DOS wildcard character
- [ is ???
- ] is ???
- = is ???
- + is ???
- < is a DOS redirection character
- > is a DOS redirection character
- " is used by DOS to delimit file names with spaces
- , is ???
- */
- public static final char[] INVALID_FILENAME_CHARACTERS = { ':', '*', '|', '&', '/', '\\', ';', '?', '[', ']', '=', '+', '<', '>', '"', ',' };
-
- /** This encoder will convert strings into valid file names. */
- public static final XMLStringEncoder FILE_NAME_ENCODER = new XMLStringEncoder(INVALID_FILENAME_CHARACTERS);
-
- /** Windows files that are redirected to devices etc. */
- private static final String[] WINDOWS_RESERVED_FILE_NAMES = {
- "con",
- "aux",
- "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
- "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
- "prn",
- "nul"
- };
-
- /** The default length of a shortened file name. */
- public static final int MAXIMUM_SHORTENED_FILE_NAME_LENGTH = 60;
-
-
- // ********** deleting directories **********
-
- /**
- * Delete the specified directory and all of its contents.
- * <em>USE WITH CARE.</em>
- * File#deleteAll()?
- */
- public static void deleteDirectory(String directoryName) {
- deleteDirectory(new File(directoryName));
- }
-
- /**
- * Delete the specified directory and all of its contents.
- * <em>USE WITH CARE.</em>
- * File#deleteAll()?
- */
- public static void deleteDirectory(File directory) {
- deleteDirectoryContents(directory);
- if ( ! directory.delete()) {
- throw new RuntimeException("unable to delete directory: " + directory.getAbsolutePath());
- }
- }
-
- /**
- * Delete the contents of the specified directory
- * (but not the directory itself).
- * <em>USE WITH CARE.</em>
- * File#deleteFiles()
- */
- public static void deleteDirectoryContents(String directoryName) {
- deleteDirectoryContents(new File(directoryName));
- }
-
- /**
- * Delete the contents of the specified directory
- * (but not the directory itself).
- * <em>USE WITH CARE.</em>
- * File#deleteFiles()
- */
- public static void deleteDirectoryContents(File directory) {
- for (File file : directory.listFiles()) {
- if (file.isDirectory()) {
- deleteDirectory(file); // recurse through subdirectories
- } else {
- if ( ! file.delete()) {
- throw new RuntimeException("unable to delete file: " + file.getAbsolutePath());
- }
- }
- }
- }
-
-
- // ********** copying files **********
-
- /**
- * Copies the content of the source file to the destination file.
- * File#copy(File destinationFile)
- */
- public static void copyToFile(File sourceFile, File destinationFile)
- throws IOException
- {
- FileChannel sourceChannel = new FileInputStream(sourceFile).getChannel();
- FileChannel destinationChannel = new FileOutputStream(destinationFile).getChannel();
- try {
- destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
- } finally {
- sourceChannel.close();
- destinationChannel.close();
- }
- }
-
- /**
- * Copies the content of the source file to a file by
- * the same name in the destination directory.
- * File#copyToDirectory(File destinationDirectory)
- */
- public static void copyToDirectory(File sourceFile, File destinationDirectory)
- throws IOException
- {
- File destinationFile = new File(destinationDirectory, sourceFile.getName());
- destinationFile.createNewFile();
- copyToFile(sourceFile, destinationFile);
- }
-
-
- // ********** iteratoring over files and directories **********
-
- /**
- * Return an iterator on all the files in the specified directory.
- * The iterator will skip over subdirectories.
- * File#files()
- */
- public static Iterator<File> filesIn(String directoryName) {
- return filesIn(new File(directoryName));
- }
-
- /**
- * Return an iterator on all the files in the specified directory.
- * The iterator will skip over subdirectories.
- * File#files()
- */
- public static Iterator<File> filesIn(File directory) {
- return filesIn(directory.listFiles());
- }
-
- private static Iterator<File> filesIn(File[] files) {
- return new FilteringIterator<File, File>(new ArrayIterator<File>(files)) {
- @Override
- protected boolean accept(File next) {
- return next.isFile();
- }
- };
- }
-
- /**
- * Return an iterator on all the subdirectories
- * in the specified directory.
- * File#subDirectories()
- */
- public static Iterator<File> directoriesIn(String directoryName) {
- return directoriesIn(new File(directoryName));
- }
-
- /**
- * Return an iterator on all the subdirectories
- * in the specified directory.
- * File#subDirectories()
- */
- public static Iterator<File> directoriesIn(File directory) {
- return directoriesIn(directory.listFiles());
- }
-
- private static Iterator<File> directoriesIn(File[] files) {
- return new FilteringIterator<File, File>(new ArrayIterator<File>(files)) {
- @Override
- protected boolean accept(File next) {
- return next.isDirectory();
- }
- };
- }
-
- /**
- * Return an iterator on all the files under the specified
- * directory, recursing into subdirectories.
- * The iterator will skip over the subdirectories themselves.
- * File#filesRecurse()
- */
- public static Iterator<File> filesInTree(String directoryName) {
- return filesInTree(new File(directoryName));
- }
-
- /**
- * Return an iterator on all the files under the specified
- * directory, recursing into subdirectories.
- * The iterator will skip over the subdirectories themselves.
- * File#filesRecurse()
- */
- public static Iterator<File> filesInTree(File directory) {
- return filesInTreeAsSet(directory).iterator();
- }
-
- private static Set<File> filesInTreeAsSet(File directory) {
- Set<File> files = new HashSet<File>(10000);
- addFilesInTreeTo(directory, files);
- return files;
- }
-
- private static void addFilesInTreeTo(File directory, Collection<File> allFiles) {
- for (File file : directory.listFiles()) {
- if (file.isFile()) {
- allFiles.add(file);
- } else if (file.isDirectory()) {
- addFilesInTreeTo(file, allFiles);
- }
- }
- }
-
- /**
- * Return an iterator on all the directories under the specified
- * directory, recursing into subdirectories.
- * File#subDirectoriesRecurse()
- */
- public static Iterator<File> directoriesInTree(String directoryName) {
- return directoriesInTree(new File(directoryName));
- }
-
- /**
- * Return an iterator on all the directories under the specified
- * directory, recursing into subdirectories.
- * File#subDirectoriesRecurse()
- */
- @SuppressWarnings("unchecked")
- public static Iterator<File> directoriesInTree(File directory) {
- File[] files = directory.listFiles();
- return new CompositeIterator<File>(directoriesIn(files), directoriesInTrees(directoriesIn(files)));
- }
-
- private static Iterator<File> directoriesInTrees(Iterator<File> directories) {
- return new CompositeIterator<File>(
- new TransformationIterator<File, Iterator<File>>(directories) {
- @Override
- protected Iterator<File> transform(File next) {
- return FileTools.directoriesInTree(next);
- }
- }
- );
- }
-
-
- // ********** short file name manipulation **********
-
- /**
- * Strip the extension from the specified file name
- * and return the result. If the file name has no
- * extension, it is returned unchanged
- * File#basePath()
- */
- public static String stripExtension(String fileName) {
- int index = fileName.lastIndexOf('.');
- if (index == -1) {
- return fileName;
- }
- return fileName.substring(0, index);
- }
-
- /**
- * Strip the extension from the specified file's name
- * and return the result. If the file's name has no
- * extension, it is returned unchanged
- * File#basePath()
- */
- public static String stripExtension(File file) {
- return stripExtension(file.getPath());
- }
-
- /**
- * Return the extension, including the dot, of the specified file name.
- * If the file name has no extension, return an empty string.
- * File#extension()
- */
- public static String extension(String fileName) {
- int index = fileName.lastIndexOf('.');
- if (index == -1) {
- return "";
- }
- return fileName.substring(index);
- }
-
- /**
- * Return the extension, including the dot, of the specified file's name.
- * If the file's name has no extension, return an empty string.
- * File#extension()
- */
- public static String extension(File file) {
- return extension(file.getPath());
- }
-
-
- // ********** temporary directories **********
-
- /**
- * Build and return an empty temporary directory with the specified
- * name. If the directory already exists, it will be cleared out.
- * This directory will be a subdirectory of the Java temporary directory,
- * as indicated by the System property "java.io.tmpdir".
- */
- public static File emptyTemporaryDirectory(String name) {
- File dir = new File(userTemporaryDirectory(), name);
- if (dir.exists()) {
- deleteDirectoryContents(dir);
- } else {
- dir.mkdirs();
- }
- return dir;
- }
-
- /**
- * Build and return an empty temporary directory with a
- * name of "tmpdir". If the directory already exists, it will be cleared out.
- * This directory will be a subdirectory of the Java temporary directory,
- * as indicated by the System property "java.io.tmpdir".
- */
- public static File emptyTemporaryDirectory() {
- return emptyTemporaryDirectory(DEFAULT_TEMPORARY_DIRECTORY_NAME);
- }
-
- /**
- * Build and return a temporary directory with the specified
- * name. If the directory already exists, it will be left unchanged;
- * if it does not already exist, it will be created.
- * This directory will be a subdirectory of the Java temporary directory,
- * as indicated by the System property "java.io.tmpdir".
- */
- public static File temporaryDirectory(String name) {
- File dir = new File(userTemporaryDirectory(), name);
- if ( ! dir.exists()) {
- dir.mkdirs();
- }
- return dir;
- }
-
- /**
- * Build and return a temporary directory with a name of
- * "tmpdir". If the directory already exists, it will be left unchanged;
- * if it does not already exist, it will be created.
- * This directory will be a subdirectory of the Java temporary directory,
- * as indicated by the System property "java.io.tmpdir".
- */
- public static File temporaryDirectory() {
- return temporaryDirectory(DEFAULT_TEMPORARY_DIRECTORY_NAME);
- }
-
- /**
- * Build and return a *new* temporary directory with the specified
- * prefix. The prefix will be appended with a number that
- * is incremented, starting with 1, until a non-pre-existing directory
- * is found and successfully created. This directory will be a
- * subdirectory of the Java temporary directory, as indicated by
- * the System property "java.io.tmpdir".
- */
- public static File newTemporaryDirectory(String prefix) {
- if ( ! prefix.endsWith(".")) {
- prefix = prefix + ".";
- }
- File dir;
- int i = 0;
- do {
- i++;
- dir = new File(userTemporaryDirectory(), prefix + i);
- } while ( ! dir.mkdirs());
- return dir;
- }
-
- /**
- * Build and return a *new* temporary directory with a
- * prefix of "tmpdir". This prefix will be appended with a number that
- * is incremented, starting with 1, until a non-pre-existing directory
- * is found and successfully created. This directory will be a
- * subdirectory of the Java temporary directory, as indicated by
- * the System property "java.io.tmpdir".
- */
- public static File newTemporaryDirectory() {
- return newTemporaryDirectory(DEFAULT_TEMPORARY_DIRECTORY_NAME);
- }
-
-
- // ********** resource files **********
-
- /**
- * Build and return a file for the specified resource.
- * The resource name must be fully-qualified, i.e. it cannot be relative
- * to the package name/directory.
- * NB: There is a bug in jdk1.4.x the prevents us from getting
- * a resource that has spaces (or other special characters) in
- * its name.... (see Sun's Java bug 4466485)
- */
- public static File resourceFile(String resourceName) throws URISyntaxException {
- if ( ! resourceName.startsWith("/")) {
- throw new IllegalArgumentException(resourceName);
- }
- return resourceFile(resourceName, FileTools.class);
- }
-
- /**
- * Build and return a file for the specified resource.
- * NB: There is a bug in jdk1.4.x the prevents us from getting
- * a resource that has spaces (or other special characters) in
- * its name.... (see Sun's Java bug 4466485)
- */
- public static File resourceFile(String resourceName, Class<?> javaClass) throws URISyntaxException {
- URL url = javaClass.getResource(resourceName);
- return buildFile(url);
- }
-
- /**
- * Build and return a file for the specified URL.
- * NB: There is a bug in jdk1.4.x the prevents us from getting
- * a resource that has spaces (or other special characters) in
- * its name.... (see Sun's Java bug 4466485)
- */
- public static File buildFile(URL url) throws URISyntaxException {
- return buildFile(url.getFile());
- }
-
- /**
- * Build and return a file for the specified file name.
- * NB: There is a bug in jdk1.4.x the prevents us from getting
- * a resource that has spaces (or other special characters) in
- * its name.... (see Sun's Java bug 4466485)
- */
- public static File buildFile(String fileName) throws URISyntaxException {
- URI uri = new URI(fileName);
- File file = new File(uri.getPath());
- return file;
- }
-
-
- // ********** "canonical" files **********
-
- /**
- * Convert the specified file into a "canonical" file.
- */
- public static File canonicalFile(File file) {
- try {
- return file.getCanonicalFile();
- } catch (IOException ioexception) {
- // settle for the absolute file
- return file.getAbsoluteFile();
- }
- }
-
- /**
- * Build an iterator that will convert the specified files
- * into "canonical" files.
- */
- public static Iterator<File> canonicalFiles(Iterator<File> files) {
- return new TransformationIterator<File, File>(files) {
- @Override
- protected File transform(File next) {
- return canonicalFile(next);
- }
- };
- }
-
- /**
- * Build an iterator that will convert the specified files
- * into "canonical" files.
- */
- public static Iterator<File> canonicalFiles(Collection<File> files) {
- return canonicalFiles(files.iterator());
- }
-
- /**
- * Convert the specified file name into a "canonical" file name.
- */
- public static String canonicalFileName(String fileName) {
- return canonicalFile(new File(fileName)).getAbsolutePath();
- }
-
- /**
- * Build an iterator that will convert the specified file names
- * into "canonical" file names.
- */
- public static Iterator<String> canonicalFileNames(Iterator<String> fileNames) {
- return new TransformationIterator<String, String>(fileNames) {
- @Override
- protected String transform(String next) {
- return canonicalFileName(next);
- }
- };
- }
-
- /**
- * Build an iterator that will convert the specified file names
- * into "canonical" file names.
- */
- public static Iterator<String> canonicalFileNames(Collection<String> fileNames) {
- return canonicalFileNames(fileNames.iterator());
- }
-
-
- // ********** file name validation **********
-
- /**
- * Return whether the specified file name is invalid.
- */
- public static boolean fileNameIsInvalid(String filename) {
- return ! fileNameIsValid(filename);
- }
-
- /**
- * Return whether the specified file name is valid.
- */
- public static boolean fileNameIsValid(String filename) {
- int len = filename.length();
- for (int i = 0; i < len; i++) {
- char filenameChar = filename.charAt(i);
- if (CollectionTools.contains(INVALID_FILENAME_CHARACTERS, filenameChar)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Convert the illegal characters in the specified file name to
- * the specified character and return the result.
- */
- public static String convertToValidFileName(String filename, char replacementChar) {
- int len = filename.length();
- StringBuilder sb = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char filenameChar = filename.charAt(i);
- if (CollectionTools.contains(INVALID_FILENAME_CHARACTERS, filenameChar)) {
- sb.append(replacementChar);
- } else {
- sb.append(filenameChar);
- }
- }
- return sb.toString();
- }
-
- /**
- * Convert the illegal characters in the specified file name to
- * periods ('.') and return the result.
- */
- public static String convertToValidFileName(String filename) {
- return convertToValidFileName(filename, '.');
- }
-
- /**
- * Return whether the specified file name is "reserved"
- * (i.e. it cannot be used for "user" files). Windows reserves
- * a number of file names (e.g. CON, AUX, PRN).
- */
- public static boolean fileNameIsReserved(String fileName) {
- if (executingOnWindows()) {
- return CollectionTools.contains(WINDOWS_RESERVED_FILE_NAMES, fileName.toLowerCase());
- }
- return false; // Unix does not have any "reserved" file names (I think...)
- }
-
- /**
- * Return whether the specified file contains any "reserved"
- * components.
- * Windows reserves a number of file names (e.g. CON, AUX, PRN);
- * and these file names cannot be used for either the names of
- * files or directories.
- */
- public static boolean fileHasAnyReservedComponents(File file) {
- File temp = file;
- while (temp != null) {
- if (fileNameIsReserved(temp.getName())) {
- return true;
- }
- temp = temp.getParentFile();
- }
- return false;
- }
-
-
- // ********** shortened file names **********
-
- /**
- * Return a shorter version of the absolute file name for the specified file.
- * The shorter version will not be longer than the maximum length.
- * The first directory (usually the drive letter) and the file name or the
- * last directory will always be added to the generated string regardless of
- * the maximum length allowed.
- */
- public static String shortenFileName(URL url) {
- return shortenFileName(url, MAXIMUM_SHORTENED_FILE_NAME_LENGTH);
- }
-
- /**
- * Return a shorter version of the absolute file name for the specified file.
- * The shorter version will not be longer than the maximum length.
- * The first directory (usually the drive letter) and the file name or the
- * last directory will always be added to the generated string regardless of
- * the maximum length allowed.
- */
- public static String shortenFileName(URL url, int maxLength) {
- File file;
- try {
- file = buildFile(url);
- } catch (URISyntaxException e) {
- file = new File(url.getFile());
- }
- return shortenFileName(file, maxLength);
- }
-
- /**
- * Return a shorter version of the absolute file name for the specified file.
- * The shorter version will not be longer than the maximum length.
- * The first directory (usually the drive letter) and the file name or the
- * last directory will always be added to the generated string regardless of
- * the maximum length allowed.
- */
- public static String shortenFileName(File file) {
- return shortenFileName(file, MAXIMUM_SHORTENED_FILE_NAME_LENGTH);
- }
-
- /**
- * Return a shorter version of the absolute file name for the specified file.
- * The shorter version will not be longer than the maximum length.
- * The first directory (usually the drive letter) and the file name or the
- * last directory will always be added to the generated string regardless of
- * the maximum length allowed.
- */
- public static String shortenFileName(File file, int maxLength) {
- String absoluteFileName = canonicalFile(file).getAbsolutePath();
- if (absoluteFileName.length() <= maxLength) {
- // no need to shorten
- return absoluteFileName;
- }
-
- // break down the path into its components
- String fs = File.separator;
- String[] paths = absoluteFileName.split("\\" + fs);
-
- if (paths.length <= 1) {
- // e.g. "C:\"
- return paths[0];
- }
-
- if (paths.length == 2) {
- // e.g. "C:\MyReallyLongFileName.ext" or "C:\MyReallyLongDirectoryName"
- // return the complete file name since this is a minimum requirement,
- // regardless of the maximum length allowed
- return absoluteFileName;
- }
-
- StringBuilder sb = new StringBuilder();
- sb.append(paths[0]); // always add the first directory, which is usually the drive letter
-
- // Keep the index of insertion into the string buffer
- int insertIndex = sb.length();
-
- sb.append(fs);
- sb.append(paths[paths.length - 1]); // append the file name or the last directory
-
- maxLength -= 4; // -4 for "/..."
-
- int currentLength = sb.length() - 4; // -4 for "/..."
- int leftIndex = 1; // 1 to skip the root directory
- int rightIndex = paths.length - 2; // -1 for the file name or the last directory
-
- boolean canAddFromLeft = true;
- boolean canAddFromRight = true;
-
- // Add each directory, the insertion is going in both direction: left and
- // right, once a side can't be added, the other side is still continuing
- // until both can't add anymore
- while (true) {
- if (!canAddFromLeft && !canAddFromRight)
- break;
-
- if (canAddFromRight) {
- String rightDirectory = paths[rightIndex];
- int rightLength = rightDirectory.length();
-
- // Add the directory on the right side of the loop
- if (currentLength + rightLength + 1 <= maxLength) {
- sb.insert(insertIndex, fs);
- sb.insert(insertIndex + 1, rightDirectory);
-
- currentLength += rightLength + 1;
- rightIndex--;
-
- // The right side is now overlapping the left side, that means
- // we can't add from the right side anymore
- if (leftIndex >= rightIndex) {
- canAddFromRight = false;
- }
- } else {
- canAddFromRight = false;
- }
- }
-
- if (canAddFromLeft) {
- String leftDirectory = paths[leftIndex];
- int leftLength = leftDirectory.length();
-
- // Add the directory on the left side of the loop
- if (currentLength + leftLength + 1 <= maxLength) {
- sb.insert(insertIndex, fs);
- sb.insert(insertIndex + 1, leftDirectory);
-
- insertIndex += leftLength + 1;
- currentLength += leftLength + 1;
- leftIndex++;
-
- // The left side is now overlapping the right side, that means
- // we can't add from the left side anymore
- if (leftIndex >= rightIndex) {
- canAddFromLeft = false;
- }
- } else {
- canAddFromLeft = false;
- }
- }
- }
-
- if (leftIndex <= rightIndex) {
- sb.insert(insertIndex, fs);
- sb.insert(insertIndex + 1, "...");
- }
-
- return sb.toString();
- }
-
-
- // ********** system properties **********
-
- /**
- * Return a file representing the user's home directory.
- */
- public static File userHomeDirectory() {
- return new File(USER_HOME_DIRECTORY_NAME);
- }
-
- /**
- * Return a file representing the user's temporary directory.
- */
- public static File userTemporaryDirectory() {
- return new File(USER_TEMPORARY_DIRECTORY_NAME);
- }
-
- /**
- * Return a file representing the current working directory.
- */
- public static File currentWorkingDirectory() {
- return new File(CURRENT_WORKING_DIRECTORY_NAME);
- }
-
-
- // ********** miscellaneous **********
-
- private static boolean executingOnWindows() {
- return executingOn("Windows");
- }
-
-// private static boolean executingOnLinux() {
-// return executingOn("Linux");
-// }
-//
- private static boolean executingOn(String osName) {
- return System.getProperty("os.name").indexOf(osName) != -1;
- }
-
- /**
- * Return only the files that fit the filter.
- * File#files(FileFilter fileFilter)
- */
- public static Iterator<File> filter(Iterator<File> files, final FileFilter fileFilter) {
- return new FilteringIterator<File, File>(files) {
- @Override
- protected boolean accept(File next) {
- return fileFilter.accept(next);
- }
- };
- }
-
- /**
- * Return a file that is a re-specification of the specified
- * file, relative to the specified directory.
- * Linux/Unix/Mac:
- * convertToRelativeFile(/foo/bar/baz.java, /foo)
- * => bar/baz.java
- * Windows:
- * convertToRelativeFile(C:\foo\bar\baz.java, C:\foo)
- * => bar/baz.java
- * The file can be either a file or a directory; the directory
- * *should* be a directory.
- * If the file is already relative or it cannot be made relative
- * to the directory, it will be returned unchanged.
- *
- * NB: This method has been tested on Windows and Linux,
- * but not Mac (but the Mac is Unix-based these days, so
- * it shouldn't be a problem...).
- */
- public static File convertToRelativeFile(final File file, final File dir) {
- // check whether the file is already relative
- if ( ! file.isAbsolute()) {
- return file; // return unchanged
- }
-
- File cFile = canonicalFile(file);
- File cDir = canonicalFile(dir);
-
- // the two are the same directory
- if (cFile.equals(cDir)) {
- return new File(".");
- }
-
- File[] filePathFiles = pathFiles(cFile);
- File[] dirPathFiles = pathFiles(cDir);
-
- // Windows only (?): the roots are different - e.g. D:\ vs. C:\
- if ( ! dirPathFiles[0].equals(filePathFiles[0])) {
- return file; // return unchanged
- }
-
- // at this point we know the root is the same, now find how much is in common
- int i = 0; // this will point at the first miscompare
- while ((i < dirPathFiles.length) && (i < filePathFiles.length)) {
- if (dirPathFiles[i].equals(filePathFiles[i])) {
- i++;
- } else {
- break;
- }
- }
- // save our current position
- int firstMismatch = i;
-
- // check whether the file is ABOVE the directory: ../..
- if (firstMismatch == filePathFiles.length) {
- return relativeParentFile(dirPathFiles.length - firstMismatch);
- }
-
- // build a new file from the path beyond the matching portions
- File diff = new File(filePathFiles[i].getName());
- while (++i < filePathFiles.length) {
- diff = new File(diff, filePathFiles[i].getName());
- }
-
- // check whether the file is BELOW the directory: subdir1/subdir2/file.ext
- if (firstMismatch == dirPathFiles.length) {
- return diff;
- }
-
- // the file must be a PEER of the directory: ../../subdir1/subdir2/file.ext
- return new File(relativeParentFile(dirPathFiles.length - firstMismatch), diff.getPath());
- }
-
- /**
- * Return a file that is a re-specification of the specified
- * file, relative to the current working directory.
- * Linux/Unix/Mac (CWD = /foo):
- * convertToRelativeFile(/foo/bar/baz.java)
- * => bar/baz.java
- * Windows (CWD = C:\foo):
- * convertToRelativeFile(C:\foo\bar\baz.java)
- * => bar/baz.java
- * The file can be either a file or a directory.
- * If the file is already relative or it cannot be made relative
- * to the directory, it will be returned unchanged.
- *
- * NB: This method has been tested on Windows and Linux,
- * but not Mac (but the Mac is Unix-based these days, so
- * it shouldn't be a problem...).
- */
- public static File convertToRelativeFile(final File file) {
- return convertToRelativeFile(file, currentWorkingDirectory());
- }
-
- /**
- * Return an array of files representing the path to the specified
- * file. For example:
- * C:/foo/bar/baz.txt =>
- * { C:/, C:/foo, C:/foo/bar, C:/foo/bar/baz.txt }
- */
- private static File[] pathFiles(File file) {
- List<File> path = new ArrayList<File>();
- for (File f = file; f != null; f = f.getParentFile()) {
- path.add(f);
- }
- Collections.reverse(path);
- return path.toArray(new File[path.size()]);
- }
-
- /**
- * Return a file with the specified (non-zero) number of relative
- * file names, e.g. xxx(3) => ../../..
- */
- private static File relativeParentFile(int len) {
- if (len <= 0) {
- throw new IllegalArgumentException("length must be greater than zero: " + len);
- }
- File result = new File("..");
- for (int i = len - 1; i-- > 0; ) {
- result = new File(result, "..");
- }
- return result;
- }
-
- /**
- * Return a file that is a re-specification of the specified
- * file, absolute to the specified directory.
- * Linux/Unix/Mac:
- * convertToAbsoluteFile(bar/baz.java, /foo)
- * => /foo/bar/baz.java
- * Windows:
- * convertToAbsoluteFile(bar/baz.java, C:\foo)
- * => C:\foo\bar\baz.java
- * The file can be either a file or a directory; the directory
- * *should* be a directory.
- * If the file is already absolute, it will be returned unchanged.
- *
- * NB: This method has been tested on Windows and Linux,
- * but not Mac (but the Mac is Unix-based these days, so
- * it shouldn't be a problem...).
- */
- public static File convertToAbsoluteFile(final File file, final File dir) {
- // check whether the file is already absolute
- if (file.isAbsolute()) {
- return file; // return unchanged
- }
- return canonicalFile(new File(dir, file.getPath()));
- }
-
- /**
- * Return a file that is a re-specification of the specified
- * file, absolute to the current working directory.
- * Linux/Unix/Mac (CWD = /foo):
- * convertToAbsoluteFile(bar/baz.java)
- * => /foo/bar/baz.java
- * Windows (CWD = C:\foo):
- * convertToAbsoluteFile(bar/baz.java)
- * => C:\foo\bar\baz.java
- * The file can be either a file or a directory.
- * If the file is already absolute, it will be returned unchanged.
- *
- * NB: This method has been tested on Windows and Linux,
- * but not Mac (but the Mac is Unix-based these days, so
- * it shouldn't be a problem...).
- */
- public static File convertToAbsoluteFile(final File file) {
- return convertToAbsoluteFile(file, currentWorkingDirectory());
- }
-
-
- // ********** constructor **********
-
- /**
- * Suppress default constructor, ensuring non-instantiability.
- */
- private FileTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/HashBag.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/HashBag.java
deleted file mode 100644
index ccf3c54d2f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/HashBag.java
+++ /dev/null
@@ -1,914 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * This class implements the <code>Bag</code> interface, backed by a
- * hash table. It makes no guarantees as to the iteration order of
- * the bag's elements; in particular, it does not guarantee that the order
- * will remain constant over time. This class permits the <code>null</code>
- * element.
- * <p>
- * This class offers constant time performance for the basic operations
- * (<code>add</code>, <code>remove</code>, <code>contains</code> and
- * <code>size</code>), assuming the hash function disperses the elements
- * properly among the buckets. Iterating over this bag requires time
- * proportional to the sum of the bag's size (the number of elements) plus the
- * "capacity" of the backing hash table (the number of buckets). Thus, it is
- * important not to set the initial capacity too high (or the load factor too
- * low) if iteration performance is important.
- * <p>
- * <b>Note that this implementation is not synchronized.</b> If multiple
- * threads access a bag concurrently, and at least one of the threads modifies
- * the bag, it <i>must</i> be synchronized externally. This is typically
- * accomplished by synchronizing on some object that naturally encapsulates
- * the bag. If no such object exists, the bag should be "wrapped" using the
- * <code>Collections.synchronizedCollection</code> method. This is
- * best done at creation time, to prevent accidental unsynchronized access
- * to the bag:
- * <pre>
- * Collection c = Collections.synchronizedCollection(new HashBag(...));
- * </pre>
- * <p>
- * The iterators returned by this class's <code>iterator</code> method are
- * <i>fail-fast</i>: if the bag is modified at any time after the iterator is
- * created, in any way except through the iterator's own <code>remove</code>
- * method, the iterator throws a <code>ConcurrentModificationException</code>.
- * Thus, in the face of concurrent modification, the iterator fails quickly
- * and cleanly, rather than risking arbitrary, non-deterministic behavior at
- * an undetermined time in the future.
- *
- * @see Collections#synchronizedCollection(Collection)
- */
-public class HashBag<E>
- extends AbstractCollection<E>
- implements Bag<E>, Cloneable, Serializable
-{
-
- /** The hash table. */
- transient Entry<E>[] table;
-
- /** The total number of entries in the bag. */
- transient int count = 0;
-
- /** The number of unique entries in the bag. */
- transient int uniqueCount = 0;
-
- /**
- * The hash table is rehashed when its size exceeds this threshold. (The
- * value of this field is (int)(capacity * loadFactor).)
- *
- * @serial
- */
- private int threshold;
-
- /**
- * The load factor for the hash table.
- *
- * @serial
- */
- private float loadFactor;
-
- /**
- * The number of times this bag has been structurally modified.
- * Structural modifications are those that change the number of entries in
- * the bag or otherwise modify its internal structure (e.g. rehash).
- * This field is used to make iterators on this bag fail-fast.
- *
- * @see java.util.ConcurrentModificationException
- */
- transient int modCount = 0;
-
- /**
- * Constructs a new, empty bag with the
- * default capacity, which is 11, and load factor, which is 0.75.
- */
- public HashBag() {
- this(11, 0.75f);
- }
-
- /**
- * Constructs a new, empty bag with the specified initial capacity
- * and default load factor, which is 0.75.
- *
- * @param initialCapacity the initial capacity of the backing map.
- * @throws IllegalArgumentException if the initial capacity is less
- * than zero.
- */
- public HashBag(int initialCapacity) {
- this(initialCapacity, 0.75f);
- }
-
- /**
- * Constructs a new, empty bag with
- * the specified initial capacity and the specified load factor.
- *
- * @param initialCapacity the initial capacity of the backing map.
- * @param loadFactor the load factor of the backing map.
- * @throws IllegalArgumentException if the initial capacity is less
- * than zero, or if the load factor is nonpositive.
- */
- public HashBag(int initialCapacity, float loadFactor) {
- if (initialCapacity < 0) {
- throw new IllegalArgumentException("Illegal Initial Capacity: " + initialCapacity);
- }
- if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
- throw new IllegalArgumentException("Illegal Load factor: " + loadFactor);
- }
- if (initialCapacity == 0) {
- initialCapacity = 1;
- }
- this.loadFactor = loadFactor;
- this.table = this.buildTable(initialCapacity);
- this.threshold = (int) (initialCapacity * loadFactor);
- }
-
- /**
- * Constructs a new bag containing the elements in the specified
- * collection. The capacity of the bag is
- * twice the size of the specified collection or 11 (whichever is
- * greater), and the default load factor, which is 0.75, is used.
- *
- * @param c the collection whose elements are to be placed into this bag.
- */
- public HashBag(Collection<? extends E> c) {
- this(Math.max(2*c.size(), 11));
- this.addAll(c);
- }
-
- /**
- * This implementation simply returns the maintained count.
- */
- @Override
- public int size() {
- return this.count;
- }
-
- /**
- * This implementation simply compares the maintained count to zero.
- */
- @Override
- public boolean isEmpty() {
- return this.count == 0;
- }
-
- /**
- * This implementation searches for the object in the hash table by calculating
- * the object's hash code and examining the entries in the corresponding hash
- * table bucket.
- */
- @Override
- public boolean contains(Object o) {
- Entry<E>[] tab = this.table;
- if (o == null) {
- for (Entry<E> e = tab[0]; e != null; e = e.next) {
- if (e.object == null) {
- return true;
- }
- }
- } else {
- int hash = o.hashCode();
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && o.equals(e.object)) {
- return true;
- }
- }
- }
- return false;
- }
-
- public int count(Object o) {
- Entry<E>[] tab = this.table;
- if (o == null) {
- for (Entry<E> e = tab[0]; e != null; e = e.next) {
- if (e.object == null) {
- return e.count;
- }
- }
- } else {
- int hash = o.hashCode();
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && o.equals(e.object)) {
- return e.count;
- }
- }
- }
- return 0;
- }
-
- /**
- * Rehashes the contents of this bag into a new hash table
- * with a larger capacity. This method is called when the
- * number of different elements in this map exceeds its
- * capacity and load factor.
- */
- private void rehash() {
- Entry<E>[] oldMap = this.table;
- int oldCapacity = oldMap.length;
-
- int newCapacity = oldCapacity * 2 + 1;
- Entry<E>[] newTable = this.buildTable(newCapacity);
-
- this.modCount++;
- this.threshold = (int) (newCapacity * this.loadFactor);
- this.table = newTable;
-
- for (int i = oldCapacity; i-- > 0; ) {
- for (Entry<E> old = oldMap[i]; old != null; ) {
- Entry<E> e = old;
- old = old.next;
-
- int index = (e.hash & 0x7FFFFFFF) % newCapacity;
- e.next = newTable[index];
- newTable[index] = e;
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private Entry<E>[] buildTable(int capacity) {
- return new Entry[capacity];
- }
-
- @SuppressWarnings("unchecked")
- private <T> Entry<E> buildEntry(int hash, Object o, Entry<T> next) {
- return new Entry(hash, o, next);
- }
-
- @SuppressWarnings("unchecked")
- private <T> Entry<E> buildEntry(int hash, Object o, int cnt, Entry<T> next) {
- return new Entry(hash, o, cnt, next);
- }
-
- /**
- * This implementation searches for the object in the hash table by calculating
- * the object's hash code and examining the entries in the corresponding hash
- * table bucket.
- */
- @Override
- public boolean add(E o) {
- this.modCount++;
- Entry<E>[] tab = this.table;
- int hash = 0;
- int index = 0;
-
- // if the object is already in the bag, simply bump its count
- if (o == null) {
- for (Entry<E> e = tab[0]; e != null; e = e.next) {
- if (e.object == null) {
- e.count++;
- this.count++;
- return true;
- }
- }
- } else {
- hash = o.hashCode();
- index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && o.equals(e.object)) {
- e.count++;
- this.count++;
- return true;
- }
- }
- }
-
- // rehash the table if the threshold is exceeded
- if (this.uniqueCount >= this.threshold) {
- this.rehash();
- tab = this.table;
- index = (hash & 0x7FFFFFFF) % tab.length;
- }
-
- // create the new entry and put it in the table
- Entry<E> e = this.buildEntry(hash, o, tab[index]);
- tab[index] = e;
- this.count++;
- this.uniqueCount++;
- return true;
- }
-
- /**
- * This implementation searches for the object in the hash table by calculating
- * the object's hash code and examining the entries in the corresponding hash
- * table bucket.
- */
- public boolean add(E o, int cnt) {
- if (cnt <= 0) {
- return false;
- }
- this.modCount++;
- Entry<E>[] tab = this.table;
- int hash = 0;
- int index = 0;
-
- // if the object is already in the bag, simply bump its count
- if (o == null) {
- for (Entry<E> e = tab[0]; e != null; e = e.next) {
- if (e.object == null) {
- e.count += cnt;
- this.count += cnt;
- return true;
- }
- }
- } else {
- hash = o.hashCode();
- index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && o.equals(e.object)) {
- e.count += cnt;
- this.count += cnt;
- return true;
- }
- }
- }
-
- // rehash the table if the threshold is exceeded
- if (this.uniqueCount >= this.threshold) {
- this.rehash();
- tab = this.table;
- index = (hash & 0x7FFFFFFF) % tab.length;
- }
-
- // create the new entry and put it in the table
- Entry<E> e = this.buildEntry(hash, o, cnt, tab[index]);
- tab[index] = e;
- this.count += cnt;
- this.uniqueCount++;
- return true;
- }
-
- /**
- * This implementation searches for the object in the hash table by calculating
- * the object's hash code and examining the entries in the corresponding hash
- * table bucket.
- */
- @Override
- public boolean remove(Object o) {
- Entry<E>[] tab = this.table;
- if (o == null) {
- for (Entry<E> e = tab[0], prev = null; e != null; prev = e, e = e.next) {
- if (e.object == null) {
- this.modCount++;
- e.count--;
- // if we are removing the last one, remove the entry from the table
- if (e.count == 0) {
- if (prev == null) {
- tab[0] = e.next;
- } else {
- prev.next = e.next;
- }
- this.uniqueCount--;
- }
- this.count--;
- return true;
- }
- }
- } else {
- int hash = o.hashCode();
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
- if ((e.hash == hash) && o.equals(e.object)) {
- this.modCount++;
- e.count--;
- // if we are removing the last one, remove the entry from the table
- if (e.count == 0) {
- if (prev == null) {
- tab[index] = e.next;
- } else {
- prev.next = e.next;
- }
- this.uniqueCount--;
- }
- this.count--;
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * This implementation searches for the object in the hash table by calculating
- * the object's hash code and examining the entries in the corresponding hash
- * table bucket.
- */
- public boolean remove(Object o, int cnt) {
- if (cnt <= 0) {
- return false;
- }
- Entry<E>[] tab = this.table;
- if (o == null) {
- for (Entry<E> e = tab[0], prev = null; e != null; prev = e, e = e.next) {
- if (e.object == null) {
- this.modCount++;
- int cnt2 = (cnt < e.count) ? cnt : e.count;
- e.count -= cnt2;
- // if we are removing the last element(s), remove the entry from the table
- if (e.count == 0) {
- if (prev == null) {
- tab[0] = e.next;
- } else {
- prev.next = e.next;
- }
- this.uniqueCount--;
- }
- this.count -= cnt2;
- return true;
- }
- }
- } else {
- int hash = o.hashCode();
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
- if ((e.hash == hash) && o.equals(e.object)) {
- this.modCount++;
- int cnt2 = (cnt < e.count) ? cnt : e.count;
- e.count -= cnt2;
- // if we are removing the last element(s), remove the entry from the table
- if (e.count == 0) {
- if (prev == null) {
- tab[index] = e.next;
- } else {
- prev.next = e.next;
- }
- this.uniqueCount--;
- }
- this.count -= cnt2;
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * This implementation simply clears out all of the hash table buckets.
- */
- @Override
- public void clear() {
- Entry<E>[] tab = this.table;
- this.modCount++;
- for (int i = tab.length; --i >= 0; ) {
- tab[i] = null;
- }
- this.count = 0;
- this.uniqueCount = 0;
- }
-
- /**
- * Returns a shallow copy of this bag: the elements
- * themselves are not cloned.
- *
- * @return a shallow copy of this bag.
- */
- @Override
- public HashBag<E> clone() {
- try {
- @SuppressWarnings("unchecked")
- HashBag<E> clone = (HashBag<E>) super.clone();
- clone.table = this.buildTable(this.table.length);
- for (int i = this.table.length; i-- > 0; ) {
- clone.table[i] = (this.table[i] == null)
- ? null : (Entry<E>) this.table[i].clone();
- }
- clone.modCount = 0;
- return clone;
- } catch (CloneNotSupportedException e) {
- throw new InternalError();
- }
- }
-
-
- /**
- * Hash table collision list entry.
- */
- private static class Entry<E> implements Bag.Entry<E> {
- int hash;
- E object;
- int count;
- Entry<E> next;
-
- Entry(int hash, E object, Entry<E> next) {
- this(hash, object, 1, next);
- }
-
- Entry(int hash, E object, int count, Entry<E> next) {
- this.hash = hash;
- this.object = object;
- this.count = count;
- this.next = next;
- }
-
- /**
- * Cascade the clone to all the entries in the same bucket.
- */
- @Override
- @SuppressWarnings("unchecked")
- protected Entry<E> clone() {
- return new Entry(this.hash, this.object, this.count,
- (this.next == null ? null : this.next.clone()));
- }
-
- // ***** Bag.Entry implementation
- public E getElement() {
- return this.object;
- }
-
- public int getCount() {
- return this.count;
- }
-
- public int setCount(int count) {
- if (count <= 0) {
- throw new IllegalArgumentException("count must be greater than zero: " + count);
- }
- int old = this.count;
- this.count = count;
- return old;
- }
-
- @Override
- public boolean equals(Object o) {
- if ( ! (o instanceof Bag.Entry)) {
- return false;
- }
- @SuppressWarnings("unchecked")
- Bag.Entry e = (Bag.Entry) o;
- if (this.count != e.getCount()) {
- return false;
- }
- Object o1 = this.object;
- Object o2 = e.getElement();
- if (o1 == o2) {
- return true;
- }
- if (o1 == null) {
- return false;
- }
- return o1.equals(o2);
- }
-
- @Override
- public int hashCode() {
- E o = this.object;
- return (o == null) ? 0 : (this.count * o.hashCode());
- }
-
- @Override
- public String toString() {
- return this.object + "=>" + this.count;
- }
- }
-
-
- @Override
- @SuppressWarnings("unchecked")
- public Iterator<E> iterator() {
- return (this.count == 0) ? EMPTY_ITERATOR : new HashIterator();
- }
-
- @SuppressWarnings("unchecked")
- public Iterator<E> uniqueIterator() {
- return (this.count == 0) ? EMPTY_ITERATOR : new UniqueIterator();
- }
-
- @SuppressWarnings("unchecked")
- public Iterator<Bag.Entry<E>> entries() {
- return (this.count == 0) ? EMPTY_ITERATOR : new EntryIterator();
- }
-
-
- /**
- * Empty iterator that does just about nothing.
- */
- @SuppressWarnings("unchecked")
- private static final Iterator EMPTY_ITERATOR = new EmptyIterator();
-
- @SuppressWarnings("unchecked")
- private static class EmptyIterator implements Iterator {
-
- EmptyIterator() {
- super();
- }
-
- public boolean hasNext() {
- return false;
- }
-
- public Object next() {
- throw new NoSuchElementException();
- }
-
- public void remove() {
- throw new IllegalStateException();
- }
- }
-
-
- private class HashIterator implements Iterator<E> {
- private Entry<E>[] localTable = HashBag.this.table;
- private int index = this.localTable.length; // start at the end of the table
- private Entry<E> nextEntry = null;
- private int nextEntryCount = 0;
- private Entry<E> lastReturnedEntry = null;
-
- /**
- * The modCount value that the iterator believes that the backing
- * bag should have. If this expectation is violated, the iterator
- * has detected a concurrent modification.
- */
- private int expectedModCount = HashBag.this.modCount;
-
- HashIterator() {
- super();
- }
-
- public boolean hasNext() {
- Entry<E> e = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((e == null) && (i > 0)) {
- e = tab[--i]; // move backwards through the table
- }
- this.nextEntry = e;
- this.index = i;
- return e != null;
- }
-
- public E next() {
- if (HashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E> et = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((et == null) && (i > 0)) {
- et = tab[--i]; // move backwards through the table
- }
- this.nextEntry = et;
- this.index = i;
- if (et == null) {
- throw new NoSuchElementException();
- }
- Entry<E> e = this.lastReturnedEntry = this.nextEntry;
- this.nextEntryCount++;
- if (this.nextEntryCount == e.count) {
- this.nextEntry = e.next;
- this.nextEntryCount = 0;
- }
- return e.object;
- }
-
- public void remove() {
- if (this.lastReturnedEntry == null) {
- throw new IllegalStateException();
- }
- if (HashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E>[] tab = this.localTable;
- int slot = (this.lastReturnedEntry.hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[slot], prev = null; e != null; prev = e, e = e.next) {
- if (e == this.lastReturnedEntry) {
- HashBag.this.modCount++;
- this.expectedModCount++;
- e.count--;
- if (e.count == 0) {
- // if we are removing the last one, remove the entry from the table
- if (prev == null) {
- tab[slot] = e.next;
- } else {
- prev.next = e.next;
- }
- HashBag.this.uniqueCount--;
- } else {
- // slide back the count to account for the just-removed element
- this.nextEntryCount--;
- }
- HashBag.this.count--;
- this.lastReturnedEntry = null; // it cannot be removed again
- return;
- }
- }
- throw new ConcurrentModificationException();
- }
-
- }
-
-
- private class EntryIterator implements Iterator<Entry<E>> {
- private Entry<E>[] localTable = HashBag.this.table;
- private int index = this.localTable.length; // start at the end of the table
- private Entry<E> nextEntry = null;
- private Entry<E> lastReturnedEntry = null;
-
- /**
- * The modCount value that the iterator believes that the backing
- * bag should have. If this expectation is violated, the iterator
- * has detected a concurrent modification.
- */
- private int expectedModCount = HashBag.this.modCount;
-
- EntryIterator() {
- super();
- }
-
- public boolean hasNext() {
- Entry<E> e = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((e == null) && (i > 0)) {
- e = tab[--i]; // move backwards through the table
- }
- this.nextEntry = e;
- this.index = i;
- return e != null;
- }
-
- public Entry<E> next() {
- if (HashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E> et = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((et == null) && (i > 0)) {
- et = tab[--i]; // move backwards through the table
- }
- this.nextEntry = et;
- this.index = i;
- if (et == null) {
- throw new NoSuchElementException();
- }
- Entry<E> e = this.lastReturnedEntry = this.nextEntry;
- this.nextEntry = e.next;
- return e;
- }
-
- public void remove() {
- if (this.lastReturnedEntry == null) {
- throw new IllegalStateException();
- }
- if (HashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E>[] tab = this.localTable;
- int slot = (this.lastReturnedEntry.hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[slot], prev = null; e != null; prev = e, e = e.next) {
- if (e == this.lastReturnedEntry) {
- HashBag.this.modCount++;
- this.expectedModCount++;
- // remove the entry from the table
- if (prev == null) {
- tab[slot] = e.next;
- } else {
- prev.next = e.next;
- }
- HashBag.this.uniqueCount--;
- HashBag.this.count -= this.lastReturnedEntry.count;
- this.lastReturnedEntry = null; // it cannot be removed again
- return;
- }
- }
- throw new ConcurrentModificationException();
- }
-
- }
-
-
- private class UniqueIterator implements Iterator<E> {
- private EntryIterator entryIterator = new EntryIterator();
-
- UniqueIterator() {
- super();
- }
-
- public boolean hasNext() {
- return this.entryIterator.hasNext();
- }
-
- public E next() {
- return this.entryIterator.next().object;
- }
-
- public void remove() {
- this.entryIterator.remove();
- }
-
- }
-
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if ( ! (o instanceof Bag)) {
- return false;
- }
- @SuppressWarnings("unchecked")
- Bag<E> b = (Bag<E>) o;
- if (b.size() != this.size()) {
- return false;
- }
- Bag<E> clone = this.clone();
- for (E e : b) {
- if ( ! clone.remove(e)) {
- return false;
- }
- }
- return clone.isEmpty();
- }
-
- @Override
- public int hashCode() {
- int h = 0;
- for (Iterator<E> stream = this.iterator(); stream.hasNext(); ) {
- Object next = stream.next();
- if (next != null) {
- h += next.hashCode();
- }
- }
- return h;
- }
-
- /**
- * Save the state of this bag to a stream (i.e. serialize it).
- *
- * @serialData Emit the capacity of the bag (int),
- * followed by the number of unique elements in the bag (int),
- * followed by all of the bag's elements (each an Object) and
- * their counts (each an int), in no particular order.
- */
- private synchronized void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- // write out the threshold, load factor, and any hidden stuff
- s.defaultWriteObject();
-
- // write out number of buckets
- s.writeInt(this.table.length);
-
- // write out number of unique elements
- s.writeInt(this.uniqueCount);
-
- Entry<E>[] tab = this.table;
- // write out elements and counts (alternating)
- for (Entry<E> entry : tab) {
- while (entry != null) {
- s.writeObject(entry.object);
- s.writeInt(entry.count);
- entry = entry.next;
- }
- }
- }
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Reconstitute the bag from a stream (i.e. deserialize it).
- */
- private synchronized void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- // read in the threshold, loadfactor, and any hidden stuff
- s.defaultReadObject();
-
- // read in number of buckets and allocate the bucket array
- this.table = this.buildTable(s.readInt());
-
- // read in number of unique elements
- int unique = s.readInt();
-
- // read the elements and counts, and put the elements in the bag
- for (int i = 0; i < unique; i++) {
- @SuppressWarnings("unchecked")
- E element = (E) s.readObject();
- int elementCount = s.readInt();
- this.add(element, elementCount);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IdentityHashBag.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IdentityHashBag.java
deleted file mode 100644
index d56f521cac..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IdentityHashBag.java
+++ /dev/null
@@ -1,879 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * This class implements the <code>Bag</code> interface with a
- * hash table, using object-identity in place of object-equality when
- * comparing elements. In other words, in an <code>IdentityHashBag</code>,
- * two objects <code>k1</code> and <code>k2</code> are considered
- * equal if and only if <code>(k1 == k2)</code>. (In normal <code>Bag</code>
- * implementations (like <code>HashBag</code>) two objects <code>k1</code>
- * and <code>k2</code> are considered equal if and only if
- * <code>(k1 == null ? k2 == null : k1.equals(k2))</code>.)
- * <p>
- * <b>
- * This class is <i>not</i> a general-purpose <code>Bag</code>
- * implementation! While this class implements the <code>Bag</code> interface, it
- * intentionally violates <code>Bag's</code> general contract, which mandates the
- * use of the <code>equals</code> method when comparing objects. This class is
- * designed for use only in the rare cases wherein object-identity
- * semantics are required.
- * </b>
- * <p>
- * This class makes no guarantees as to the iteration order of
- * the bag's elements; in particular, it does not guarantee that the order
- * will remain constant over time. This class permits the <code>null</code>
- * element.
- * <p>
- * This class offers constant time performance for the basic operations
- * (<code>add</code>, <code>remove</code>, <code>contains</code> and
- * <code>size</code>), assuming the system identity hash function
- * ({@link System#identityHashCode(Object)}) disperses elements properly
- * among the buckets. Iterating over this bag requires time
- * proportional to the sum of the bag's size (the number of elements) plus the
- * "capacity" of the backing hash table (the number of buckets). Thus, it is
- * important not to set the initial capacity too high (or the load factor too
- * low) if iteration performance is important.
- * <p>
- * <b>Note that this implementation is not synchronized.</b> If multiple
- * threads access a bag concurrently, and at least one of the threads modifies
- * the bag, it <i>must</i> be synchronized externally. This is typically
- * accomplished by synchronizing on some object that naturally encapsulates
- * the bag. If no such object exists, the bag should be "wrapped" using the
- * <code>Collections.synchronizedCollection</code> method. This is
- * best done at creation time, to prevent accidental unsynchronized access
- * to the bag:
- * <pre>
- * Collection c = Collections.synchronizedCollection(new IdentityHashBag(...));
- * </pre>
- * <p>
- * The iterators returned by this class's <code>iterator</code> method are
- * <i>fail-fast</i>: if the bag is modified at any time after the iterator is
- * created, in any way except through the iterator's own <code>remove</code>
- * method, the iterator throws a <code>ConcurrentModificationException</code>.
- * Thus, in the face of concurrent modification, the iterator fails quickly
- * and cleanly, rather than risking arbitrary, non-deterministic behavior at
- * an undetermined time in the future.
- *
- * @see Collections#synchronizedCollection(Collection)
- */
-
-public class IdentityHashBag<E>
- extends AbstractCollection<E>
- implements Bag<E>, Cloneable, Serializable
-{
-
- /** The hash table. */
- transient Entry<E>[] table;
-
- /** The total number of entries in the bag. */
- transient int count = 0;
-
- /** The number of unique entries in the bag. */
- transient int uniqueCount = 0;
-
- /**
- * The hash table is rehashed when its size exceeds this threshold. (The
- * value of this field is (int)(capacity * loadFactor).)
- *
- * @serial
- */
- private int threshold;
-
- /**
- * The load factor for the hash table.
- *
- * @serial
- */
- private float loadFactor;
-
- /**
- * The number of times this bag has been structurally modified.
- * Structural modifications are those that change the number of entries in
- * the bag or otherwise modify its internal structure (e.g. rehash).
- * This field is used to make iterators on this bag fail-fast.
- *
- * @see java.util.ConcurrentModificationException
- */
- transient int modCount = 0;
-
- /**
- * Constructs a new, empty bag with the
- * default capacity, which is 11, and load factor, which is 0.75.
- */
- public IdentityHashBag() {
- this(11, 0.75f);
- }
-
- /**
- * Constructs a new, empty bag with the specified initial capacity
- * and default load factor, which is 0.75.
- *
- * @param initialCapacity the initial capacity of the backing map.
- * @throws IllegalArgumentException if the initial capacity is less
- * than zero.
- */
- public IdentityHashBag(int initialCapacity) {
- this(initialCapacity, 0.75f);
- }
-
- /**
- * Constructs a new, empty bag with
- * the specified initial capacity and the specified load factor.
- *
- * @param initialCapacity the initial capacity of the backing map.
- * @param loadFactor the load factor of the backing map.
- * @throws IllegalArgumentException if the initial capacity is less
- * than zero, or if the load factor is nonpositive.
- */
- public IdentityHashBag(int initialCapacity, float loadFactor) {
- if (initialCapacity < 0) {
- throw new IllegalArgumentException("Illegal Initial Capacity: " + initialCapacity);
- }
- if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
- throw new IllegalArgumentException("Illegal Load factor: " + loadFactor);
- }
- if (initialCapacity == 0) {
- initialCapacity = 1;
- }
- this.loadFactor = loadFactor;
- this.table = this.buildTable(initialCapacity);
- this.threshold = (int) (initialCapacity * loadFactor);
- }
-
- /**
- * Constructs a new bag containing the elements in the specified
- * collection. The capacity of the bag is
- * twice the size of the specified collection or 11 (whichever is
- * greater), and the default load factor, which is 0.75, is used.
- *
- * @param c the collection whose elements are to be placed into this bag.
- */
- public IdentityHashBag(Collection<? extends E> c) {
- this(Math.max(2*c.size(), 11));
- this.addAll(c);
- }
-
- /**
- * This implementation simply returns the maintained count.
- */
- @Override
- public int size() {
- return this.count;
- }
-
- /**
- * This implementation simply compares the maintained count to zero.
- */
- @Override
- public boolean isEmpty() {
- return this.count == 0;
- }
-
- /**
- * This implementation searches for the object in the hash table by
- * calculating the object's identity hash code and examining the
- * entries in the corresponding hash table bucket.
- */
- @Override
- public boolean contains(Object o) {
- Entry<E>[] tab = this.table;
- int hash = System.identityHashCode(o);
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && (e.object == o)) {
- return true;
- }
- }
- return false;
- }
-
- public int count(Object o) {
- Entry<E>[] tab = this.table;
- int hash = System.identityHashCode(o);
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && (e.object == o)) {
- return e.count;
- }
- }
- return 0;
- }
-
- /**
- * Rehashes the contents of this bag into a new hash table
- * with a larger capacity. This method is called when the
- * number of different elements in this map exceeds its
- * capacity and load factor.
- */
- private void rehash() {
- Entry<E>[] oldMap = this.table;
- int oldCapacity = oldMap.length;
-
- int newCapacity = oldCapacity * 2 + 1;
- Entry<E>[] newTable = this.buildTable(newCapacity);
-
- this.modCount++;
- this.threshold = (int) (newCapacity * this.loadFactor);
- this.table = newTable;
-
- for (int i = oldCapacity; i-- > 0; ) {
- for (Entry<E> old = oldMap[i]; old != null; ) {
- Entry<E> e = old;
- old = old.next;
-
- int index = (e.hash & 0x7FFFFFFF) % newCapacity;
- e.next = newTable[index];
- newTable[index] = e;
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private Entry<E>[] buildTable(int capacity) {
- return new Entry[capacity];
- }
-
- @SuppressWarnings("unchecked")
- private <T> Entry<E> buildEntry(int hash, Object o, Entry<T> next) {
- return new Entry(hash, o, next);
- }
-
- @SuppressWarnings("unchecked")
- private <T> Entry<E> buildEntry(int hash, Object o, int cnt, Entry<T> next) {
- return new Entry(hash, o, cnt, next);
- }
-
- /**
- * This implementation searches for the object in the hash table by
- * calculating the object's identity hash code and examining the
- * entries in the corresponding hash table bucket.
- */
- @Override
- public boolean add(E o) {
- this.modCount++;
- Entry<E>[] tab = this.table;
- int hash = 0;
- int index = 0;
-
- // if the object is already in the bag, simply bump its count
- hash = System.identityHashCode(o);
- index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && (e.object == o)) {
- e.count++;
- this.count++;
- return true;
- }
- }
-
- // rehash the table if the threshold is exceeded
- if (this.uniqueCount >= this.threshold) {
- this.rehash();
- tab = this.table;
- index = (hash & 0x7FFFFFFF) % tab.length;
- }
-
- // create the new entry and put it in the table
- Entry<E> e = this.buildEntry(hash, o, tab[index]);
- tab[index] = e;
- this.count++;
- this.uniqueCount++;
- return true;
- }
-
- /**
- * This implementation searches for the object in the hash table by
- * calculating the object's identity hash code and examining the
- * entries in the corresponding hash table bucket.
- */
- public boolean add(E o, int cnt) {
- if (cnt <= 0) {
- return false;
- }
- this.modCount++;
- Entry<E>[] tab = this.table;
- int hash = 0;
- int index = 0;
-
- // if the object is already in the bag, simply bump its count
- hash = System.identityHashCode(o);
- index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index]; e != null; e = e.next) {
- if ((e.hash == hash) && (e.object == o)) {
- e.count += cnt;
- this.count += cnt;
- return true;
- }
- }
-
- // rehash the table if the threshold is exceeded
- if (this.uniqueCount >= this.threshold) {
- this.rehash();
- tab = this.table;
- index = (hash & 0x7FFFFFFF) % tab.length;
- }
-
- // create the new entry and put it in the table
- Entry<E> e = this.buildEntry(hash, o, cnt, tab[index]);
- tab[index] = e;
- this.count += cnt;
- this.uniqueCount++;
- return true;
- }
-
- /**
- * This implementation searches for the object in the hash table by
- * calculating the object's identity hash code and examining the
- * entries in the corresponding hash table bucket.
- */
- @Override
- public boolean remove(Object o) {
- Entry<E>[] tab = this.table;
- int hash = System.identityHashCode(o);
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
- if ((e.hash == hash) && (e.object == o)) {
- this.modCount++;
- e.count--;
- // if we are removing the last one, remove the entry from the table
- if (e.count == 0) {
- if (prev == null) {
- tab[index] = e.next;
- } else {
- prev.next = e.next;
- }
- this.uniqueCount--;
- }
- this.count--;
- return true;
- }
- }
- return false;
- }
-
- /**
- * This implementation searches for the object in the hash table by
- * calculating the object's identity hash code and examining the
- * entries in the corresponding hash table bucket.
- */
- public boolean remove(Object o, int cnt) {
- if (cnt <= 0) {
- return false;
- }
- Entry<E>[] tab = this.table;
- int hash = System.identityHashCode(o);
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
- if ((e.hash == hash) && (e.object == o)) {
- this.modCount++;
- int cnt2 = (cnt < e.count) ? cnt : e.count;
- e.count -= cnt2;
- // if we are removing the last element(s), remove the entry from the table
- if (e.count == 0) {
- if (prev == null) {
- tab[index] = e.next;
- } else {
- prev.next = e.next;
- }
- this.uniqueCount--;
- }
- this.count -= cnt2;
- return true;
- }
- }
- return false;
- }
-
- /**
- * This implementation uses object-identity to determine whether
- * specified collection contains a particular element.
- */
- @Override
- public boolean removeAll(Collection<?> c) {
- return super.removeAll(this.buildIdentityHashBag(c));
- }
-
- /**
- * This implementation uses object-identity to determine whether
- * specified collection contains a particular element.
- */
- @Override
- public boolean retainAll(Collection<?> c) {
- return super.retainAll(this.buildIdentityHashBag(c));
- }
-
- @SuppressWarnings("unchecked")
- private Collection<?> buildIdentityHashBag(Collection<?> c) {
- return new IdentityHashBag(c);
- }
-
- /**
- * This implementation simply clears out all of the hash table buckets.
- */
- @Override
- public void clear() {
- Entry<E>[] tab = this.table;
- this.modCount++;
- for (int i = tab.length; --i >= 0; ) {
- tab[i] = null;
- }
- this.count = 0;
- this.uniqueCount = 0;
- }
-
- /**
- * Returns a shallow copy of this bag: the elements
- * themselves are not cloned.
- *
- * @return a shallow copy of this bag.
- */
- @Override
- public IdentityHashBag<E> clone() {
- try {
- @SuppressWarnings("unchecked")
- IdentityHashBag<E> clone = (IdentityHashBag<E>) super.clone();
- clone.table = this.buildTable(this.table.length);
- for (int i = this.table.length; i-- > 0; ) {
- clone.table[i] = (this.table[i] == null)
- ? null : (Entry<E>) this.table[i].clone();
- }
- clone.modCount = 0;
- return clone;
- } catch (CloneNotSupportedException e) {
- throw new InternalError();
- }
- }
-
-
- /**
- * Hash table collision list entry.
- */
- private static class Entry<E> implements Bag.Entry<E> {
- int hash;
- E object;
- int count;
- Entry<E> next;
-
- Entry(int hash, E object, Entry<E> next) {
- this(hash, object, 1, next);
- }
-
- Entry(int hash, E object, int count, Entry<E> next) {
- this.hash = hash;
- this.object = object;
- this.count = count;
- this.next = next;
- }
-
- /**
- * Cascade the clone to all the entries in the same bucket.
- */
- @Override
- @SuppressWarnings("unchecked")
- protected Entry<E> clone() {
- return new Entry(this.hash, this.object, this.count,
- (this.next == null ? null : this.next.clone()));
- }
-
-
- // ***** Bag.Entry implementation
- public E getElement() {
- return this.object;
- }
-
- public int getCount() {
- return this.count;
- }
-
- public int setCount(int count) {
- if (count <= 0) {
- throw new IllegalArgumentException("count must be greater than zero: " + count);
- }
- int old = this.count;
- this.count = count;
- return old;
- }
-
- @Override
- public boolean equals(Object o) {
- if ( ! (o instanceof Bag.Entry)) {
- return false;
- }
- @SuppressWarnings("unchecked")
- Bag.Entry e = (Bag.Entry) o;
- return (this.object == e.getElement())
- && (this.count == e.getCount());
- }
-
- @Override
- public int hashCode() {
- E o = this.object;
- return (o == null) ? 0 : (this.count * o.hashCode());
- }
-
- @Override
- public String toString() {
- return this.object + "=>" + this.count;
- }
- }
-
-
- @Override
- @SuppressWarnings("unchecked")
- public Iterator<E> iterator() {
- return (this.count == 0) ? EMPTY_ITERATOR : new HashIterator();
- }
-
- /**
- * Return an iterator that returns each item in the bag
- * once and only once, irrespective of how many times
- * the item was added to the bag.
- */
- @SuppressWarnings("unchecked")
- public Iterator<E> uniqueIterator() {
- return (this.count == 0) ? EMPTY_ITERATOR : new UniqueIterator();
- }
-
- @SuppressWarnings("unchecked")
- public Iterator<Bag.Entry<E>> entries() {
- return (this.count == 0) ? EMPTY_ITERATOR : new EntryIterator();
- }
-
-
- /**
- * Empty iterator that does just about nothing.
- */
- @SuppressWarnings("unchecked")
- private static final Iterator EMPTY_ITERATOR = new EmptyIterator();
-
- @SuppressWarnings("unchecked")
- private static class EmptyIterator implements Iterator {
-
- EmptyIterator() {
- super();
- }
-
- public boolean hasNext() {
- return false;
- }
-
- public Object next() {
- throw new NoSuchElementException();
- }
-
- public void remove() {
- throw new IllegalStateException();
- }
- }
-
-
- private class HashIterator implements Iterator<E> {
- private Entry<E>[] localTable = IdentityHashBag.this.table;
- private int index = this.localTable.length; // start at the end of the table
- private Entry<E> nextEntry = null;
- private int nextEntryCount = 0;
- private Entry<E> lastReturnedEntry = null;
-
- /**
- * The modCount value that the iterator believes that the backing
- * bag should have. If this expectation is violated, the iterator
- * has detected a concurrent modification.
- */
- private int expectedModCount = IdentityHashBag.this.modCount;
-
- HashIterator() {
- super();
- }
-
- public boolean hasNext() {
- Entry<E> e = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((e == null) && (i > 0)) {
- e = tab[--i]; // move backwards through the table
- }
- this.nextEntry = e;
- this.index = i;
- return e != null;
- }
-
- public E next() {
- if (IdentityHashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E> et = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((et == null) && (i > 0)) {
- et = tab[--i]; // move backwards through the table
- }
- this.nextEntry = et;
- this.index = i;
- if (et == null) {
- throw new NoSuchElementException();
- }
- Entry<E> e = this.lastReturnedEntry = this.nextEntry;
- this.nextEntryCount++;
- if (this.nextEntryCount == e.count) {
- this.nextEntry = e.next;
- this.nextEntryCount = 0;
- }
- return e.object;
- }
-
- public void remove() {
- if (this.lastReturnedEntry == null) {
- throw new IllegalStateException();
- }
- if (IdentityHashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E>[] tab = this.localTable;
- int slot = (this.lastReturnedEntry.hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[slot], prev = null; e != null; prev = e, e = e.next) {
- if (e == this.lastReturnedEntry) {
- IdentityHashBag.this.modCount++;
- this.expectedModCount++;
- e.count--;
- if (e.count == 0) {
- // if we are removing the last one, remove the entry from the table
- if (prev == null) {
- tab[slot] = e.next;
- } else {
- prev.next = e.next;
- }
- IdentityHashBag.this.uniqueCount--;
- } else {
- // slide back the count to account for the just-removed element
- this.nextEntryCount--;
- }
- IdentityHashBag.this.count--;
- this.lastReturnedEntry = null; // it cannot be removed again
- return;
- }
- }
- throw new ConcurrentModificationException();
- }
- }
-
-
- private class EntryIterator implements Iterator<Entry<E>> {
- private Entry<E>[] localTable = IdentityHashBag.this.table;
- private int index = this.localTable.length; // start at the end of the table
- private Entry<E> nextEntry = null;
- private Entry<E> lastReturnedEntry = null;
-
- /**
- * The modCount value that the iterator believes that the backing
- * bag should have. If this expectation is violated, the iterator
- * has detected a concurrent modification.
- */
- private int expectedModCount = IdentityHashBag.this.modCount;
-
- EntryIterator() {
- super();
- }
-
- public boolean hasNext() {
- Entry<E> e = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((e == null) && (i > 0)) {
- e = tab[--i]; // move backwards through the table
- }
- this.nextEntry = e;
- this.index = i;
- return e != null;
- }
-
- public Entry<E> next() {
- if (IdentityHashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E> et = this.nextEntry;
- int i = this.index;
- Entry<E>[] tab = this.localTable;
- // Use locals for faster loop iteration
- while ((et == null) && (i > 0)) {
- et = tab[--i]; // move backwards through the table
- }
- this.nextEntry = et;
- this.index = i;
- if (et == null) {
- throw new NoSuchElementException();
- }
- Entry<E> e = this.lastReturnedEntry = this.nextEntry;
- this.nextEntry = e.next;
- return e;
- }
-
- public void remove() {
- if (this.lastReturnedEntry == null) {
- throw new IllegalStateException();
- }
- if (IdentityHashBag.this.modCount != this.expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Entry<E>[] tab = this.localTable;
- int slot = (this.lastReturnedEntry.hash & 0x7FFFFFFF) % tab.length;
- for (Entry<E> e = tab[slot], prev = null; e != null; prev = e, e = e.next) {
- if (e == this.lastReturnedEntry) {
- IdentityHashBag.this.modCount++;
- this.expectedModCount++;
- // remove the entry from the table
- if (prev == null) {
- tab[slot] = e.next;
- } else {
- prev.next = e.next;
- }
- IdentityHashBag.this.uniqueCount--;
- IdentityHashBag.this.count -= this.lastReturnedEntry.count;
- this.lastReturnedEntry = null; // it cannot be removed again
- return;
- }
- }
- throw new ConcurrentModificationException();
- }
-
- }
-
-
- private class UniqueIterator implements Iterator<E> {
- private EntryIterator entryIterator = new EntryIterator();
-
- UniqueIterator() {
- super();
- }
-
- public boolean hasNext() {
- return this.entryIterator.hasNext();
- }
-
- public E next() {
- return this.entryIterator.next().object;
- }
-
- public void remove() {
- this.entryIterator.remove();
- }
-
- }
-
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (o instanceof IdentityHashBag) {
- @SuppressWarnings("unchecked")
- IdentityHashBag<E> b = (IdentityHashBag<E>) o;
- if (b.size() != this.size()) {
- return false;
- }
- IdentityHashBag<E> clone = this.clone();
- for (E e : b) {
- if ( ! clone.remove(e)) {
- return false;
- }
- }
- return clone.isEmpty();
- } else if (o instanceof Bag) {
- // hmmm...
- return this.buildBag().equals(o);
- } else {
- return false;
- }
- }
-
- @SuppressWarnings("unchecked")
- private Bag<E> buildBag() {
- return new HashBag(this);
- }
-
- @Override
- public int hashCode() {
- int h = 0;
- for (E e : this) {
- h += System.identityHashCode(e);
- }
- return h;
- }
-
- /**
- * Save the state of this bag to a stream (i.e. serialize it).
- *
- * @serialData Emit the capacity of the bag (int),
- * followed by the number of unique elements in the bag (int),
- * followed by all of the bag's elements (each an Object) and
- * their counts (each an int), in no particular order.
- */
- private synchronized void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- // write out the threshold, load factor, and any hidden stuff
- s.defaultWriteObject();
-
- // write out number of buckets
- s.writeInt(this.table.length);
-
- // write out number of unique elements
- s.writeInt(this.uniqueCount);
-
- Entry<E>[] tab = this.table;
- // write out elements and counts (alternating)
- for (Entry<E> entry : tab) {
- while (entry != null) {
- s.writeObject(entry.object);
- s.writeInt(entry.count);
- entry = entry.next;
- }
- }
- }
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Reconstitute the bag from a stream (i.e. deserialize it).
- */
- private synchronized void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- // read in the threshold, loadfactor, and any hidden stuff
- s.defaultReadObject();
-
- // read in number of buckets and allocate the bucket array
- this.table = this.buildTable(s.readInt());
-
- // read in number of unique elements
- int unique = s.readInt();
-
- // read the elements and counts, and put the elements in the bag
- for (int i = 0; i < unique; i++) {
- @SuppressWarnings("unchecked")
- E element = (E) s.readObject();
- int elementCount = s.readInt();
- for (int j = 0; j < elementCount; j++) {
- this.add(element);
- }
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java
deleted file mode 100644
index f2afb1d4e6..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/IndentingPrintWriter.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.PrintWriter;
-import java.io.Writer;
-
-/**
- * Extend PrintWriter to automatically indent new lines.
- */
-public class IndentingPrintWriter extends PrintWriter {
-
- private final String indent;
- private int indentLevel;
- private boolean needsIndent;
-
- public static String DEFAULT_INDENT = "\t";
-
-
- /**
- * Construct a writer that indents with tabs.
- */
- public IndentingPrintWriter(Writer out) {
- this(out, DEFAULT_INDENT);
- }
-
- /**
- * Construct a writer that indents with the specified string.
- */
- public IndentingPrintWriter(Writer out, String indent) {
- super(out);
- this.indent = indent;
- this.indentLevel = 0;
- this.needsIndent = true;
- }
-
- /**
- * Set flag so following line is indented.
- */
- @Override
- public void println() {
- synchronized (this.lock) {
- super.println();
- this.needsIndent = true;
- }
- }
-
- /**
- * Print the appropriate indent.
- */
- private void printIndent() {
- if (this.needsIndent) {
- this.needsIndent = false;
- for (int i = this.indentLevel; i-- > 0; ) {
- this.print(this.indent);
- }
- }
- }
-
- /**
- * Write a portion of an array of characters.
- */
- @Override
- public void write(char buf[], int off, int len) {
- synchronized (this.lock) {
- this.printIndent();
- super.write(buf, off, len);
- }
- }
-
- /**
- * Write a single character.
- */
- @Override
- public void write(int c) {
- synchronized (this.lock) {
- this.printIndent();
- super.write(c);
- }
- }
-
- /**
- * Write a portion of a string.
- */
- @Override
- public void write(String s, int off, int len) {
- synchronized (this.lock) {
- this.printIndent();
- super.write(s, off, len);
- }
- }
-
- /**
- * Bump the indent level.
- */
- public void indent() {
- this.incrementIndentLevel();
- }
-
- /**
- * Decrement the indent level.
- */
- public void undent() {
- this.decrementIndentLevel();
- }
-
- /**
- * Bump the indent level.
- */
- public void incrementIndentLevel() {
- synchronized (this.lock) {
- this.indentLevel++;
- }
- }
-
- /**
- * Decrement the indent level.
- */
- public void decrementIndentLevel() {
- synchronized (this.lock) {
- this.indentLevel--;
- }
- }
-
- /**
- * Return the current indent level.
- */
- public int indentLevel() {
- return this.indentLevel;
- }
-
- /**
- * Allow the indent level to be set directly.
- */
- public void setIndentLevel(int indentLevel) {
- synchronized (this.lock) {
- this.indentLevel = indentLevel;
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java
deleted file mode 100644
index 34aff52d7a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCTools.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.sql.Types;
-import java.util.HashMap;
-import org.eclipse.jpt.utility.JavaType;
-
-/**
- * Helper methods for dealing with the JDBC API.
- */
-public final class JDBCTools {
-
-
- /**
- * Return the JDBC type corresponding to the specified class.
- * @see java.sql.Types
- */
- public static JDBCType jdbcTypeForClassNamed(String className) {
- JavaToJDBCTypeMapping mapping = javaToJDBCTypeMapping(className);
- return (mapping == null) ? DEFAULT_JDBC_TYPE : mapping.getJDBCType();
- }
-
- /**
- * Return the JDBC type corresponding to the specified class.
- * @see java.sql.Types
- */
- public static JDBCType jdbcTypeFor(Class<?> javaClass) {
- return jdbcTypeForClassNamed(javaClass.getName());
- }
-
- /**
- * Return the JDBC type corresponding to the specified class.
- * @see java.sql.Types
- */
- public static JDBCType jdbcTypeFor(JavaType javaType) {
- return jdbcTypeForClassNamed(javaType.getJavaClassName());
- }
-
- /**
- * Return the Java type corresponding to the specified JDBC type.
- * @see java.sql.Types
- */
- public static JavaType javaTypeForJDBCTypeNamed(String jdbcTypeName) {
- JDBCToJavaTypeMapping mapping = jdbcToJavaTypeMapping(jdbcTypeName);
- return (mapping == null) ? DEFAULT_JAVA_TYPE : mapping.getJavaType();
- }
-
- /**
- * Return the Java type corresponding to the specified JDBC type.
- * @see java.sql.Types
- */
- public static JavaType javaTypeFor(JDBCType jdbcType) {
- return javaTypeForJDBCTypeNamed(jdbcType.name());
- }
-
- /**
- * Return the Java type corresponding to the specified JDBC type.
- * @see java.sql.Types
- */
- public static JavaType javaTypeForJDBCTypeCode(int jdbcTypeCode) {
- return javaTypeFor(JDBCType.type(jdbcTypeCode));
- }
-
-
- // ********** internal stuff **********
-
-
- // ********** JDBC => Java **********
-
- /**
- * JDBC => Java type mappings, keyed by JDBC type name (e.g. "VARCHAR")
- */
- private static HashMap<String, JDBCToJavaTypeMapping> JDBC_TO_JAVA_TYPE_MAPPINGS; // pseudo 'final' - lazy-initialized
- private static final JavaType DEFAULT_JAVA_TYPE = new SimpleJavaType(java.lang.Object.class); // TODO Object is the default?
-
-
- private static JDBCToJavaTypeMapping jdbcToJavaTypeMapping(String jdbcTypeName) {
- return jdbcToJavaTypeMappings().get(jdbcTypeName);
- }
-
- private static synchronized HashMap<String, JDBCToJavaTypeMapping> jdbcToJavaTypeMappings() {
- if (JDBC_TO_JAVA_TYPE_MAPPINGS == null) {
- JDBC_TO_JAVA_TYPE_MAPPINGS = buildJDBCToJavaTypeMappings();
- }
- return JDBC_TO_JAVA_TYPE_MAPPINGS;
- }
-
- private static HashMap<String, JDBCToJavaTypeMapping> buildJDBCToJavaTypeMappings() {
- HashMap<String, JDBCToJavaTypeMapping> mappings = new HashMap<String, JDBCToJavaTypeMapping>();
- addJDBCToJavaTypeMappingsTo(mappings);
- return mappings;
- }
-
- /**
- * hard code the default mappings from the JDBC types to the
- * appropriate Java types
- * @see java.sql.Types
- * see "JDBC 3.0 Specification" Appendix B
- */
- private static void addJDBCToJavaTypeMappingsTo(HashMap<String, JDBCToJavaTypeMapping> mappings) {
- addJDBCToJavaTypeMappingTo(Types.ARRAY, java.sql.Array.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.BIGINT, long.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.BINARY, byte[].class, mappings);
- addJDBCToJavaTypeMappingTo(Types.BIT, boolean.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.BLOB, java.sql.Blob.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.BOOLEAN, boolean.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.CHAR, java.lang.String.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.CLOB, java.sql.Clob.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.DATALINK, java.net.URL.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.DATE, java.sql.Date.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.DECIMAL, java.math.BigDecimal.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.DISTINCT, java.lang.Object.class, mappings); // ???
- addJDBCToJavaTypeMappingTo(Types.DOUBLE, double.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.FLOAT, double.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.INTEGER, int.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.JAVA_OBJECT, java.lang.Object.class, mappings); // ???
- addJDBCToJavaTypeMappingTo(Types.LONGVARBINARY, byte[].class, mappings);
- addJDBCToJavaTypeMappingTo(Types.LONGVARCHAR, java.lang.String.class, mappings);
- // not sure why this is defined in java.sql.Types
-// addJDBCToJavaTypeMappingTo(Types.NULL, java.lang.Object.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.NUMERIC, java.math.BigDecimal.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.OTHER, java.lang.Object.class, mappings); // ???
- addJDBCToJavaTypeMappingTo(Types.REAL, float.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.REF, java.sql.Ref.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.SMALLINT, short.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.STRUCT, java.sql.Struct.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.TIME, java.sql.Time.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.TIMESTAMP, java.sql.Timestamp.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.TINYINT, byte.class, mappings);
- addJDBCToJavaTypeMappingTo(Types.VARBINARY, byte[].class, mappings);
- addJDBCToJavaTypeMappingTo(Types.VARCHAR, java.lang.String.class, mappings);
- }
-
- private static void addJDBCToJavaTypeMappingTo(int jdbcTypeCode, Class<?> javaClass, HashMap<String, JDBCToJavaTypeMapping> mappings) {
- // check for duplicates
- JDBCType jdbcType = JDBCType.type(jdbcTypeCode);
- Object prev = mappings.put(jdbcType.name(), buildJDBCToJavaTypeMapping(jdbcType, javaClass));
- if (prev != null) {
- throw new IllegalArgumentException("duplicate JDBC type: " + jdbcType.name());
- }
- }
-
- private static JDBCToJavaTypeMapping buildJDBCToJavaTypeMapping(JDBCType jdbcType, Class<?> javaClass) {
- return new JDBCToJavaTypeMapping(jdbcType, new SimpleJavaType(javaClass));
- }
-
-
- // ********** Java => JDBC **********
-
- /**
- * Java => JDBC type mappings, keyed by Java class name (e.g. "java.lang.Object")
- */
- private static HashMap<String, JavaToJDBCTypeMapping> JAVA_TO_JDBC_TYPE_MAPPINGS; // pseudo 'final' - lazy-initialized
- private static final JDBCType DEFAULT_JDBC_TYPE = JDBCType.type(Types.VARCHAR); // TODO VARCHAR is the default?
-
-
- private static JavaToJDBCTypeMapping javaToJDBCTypeMapping(String className) {
- return javaToJDBCTypeMappings().get(className);
- }
-
- private static synchronized HashMap<String, JavaToJDBCTypeMapping> javaToJDBCTypeMappings() {
- if (JAVA_TO_JDBC_TYPE_MAPPINGS == null) {
- JAVA_TO_JDBC_TYPE_MAPPINGS = buildJavaToJDBCTypeMappings();
- }
- return JAVA_TO_JDBC_TYPE_MAPPINGS;
- }
-
- private static HashMap<String, JavaToJDBCTypeMapping> buildJavaToJDBCTypeMappings() {
- HashMap<String, JavaToJDBCTypeMapping> mappings = new HashMap<String, JavaToJDBCTypeMapping>();
- addJavaToJDBCTypeMappingsTo(mappings);
- return mappings;
- }
-
- /**
- * hard code the default mappings from the Java types to the
- * appropriate JDBC types
- * @see java.sql.Types
- * see "JDBC 3.0 Specification" Appendix B
- */
- private static void addJavaToJDBCTypeMappingsTo(HashMap<String, JavaToJDBCTypeMapping> mappings) {
- // primitives
- addJavaToJDBCTypeMappingTo(boolean.class, Types.BIT, mappings);
- addJavaToJDBCTypeMappingTo(byte.class, Types.TINYINT, mappings);
- addJavaToJDBCTypeMappingTo(double.class, Types.DOUBLE, mappings);
- addJavaToJDBCTypeMappingTo(float.class, Types.REAL, mappings);
- addJavaToJDBCTypeMappingTo(int.class, Types.INTEGER, mappings);
- addJavaToJDBCTypeMappingTo(long.class, Types.BIGINT, mappings);
- addJavaToJDBCTypeMappingTo(short.class, Types.SMALLINT, mappings);
-
- // reference classes
- addJavaToJDBCTypeMappingTo(java.lang.Boolean.class, Types.BIT, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Byte.class, Types.TINYINT, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Double.class, Types.DOUBLE, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Float.class, Types.REAL, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Integer.class, Types.INTEGER, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Long.class, Types.BIGINT, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Short.class, Types.SMALLINT, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.String.class, Types.VARCHAR, mappings);
- addJavaToJDBCTypeMappingTo(java.math.BigDecimal.class, Types.NUMERIC, mappings);
- addJavaToJDBCTypeMappingTo(java.net.URL.class, Types.DATALINK, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Array.class, Types.ARRAY, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Blob.class, Types.BLOB, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Clob.class, Types.CLOB, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Date.class, Types.DATE, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Ref.class, Types.REF, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Struct.class, Types.STRUCT, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Time.class, Types.TIME, mappings);
- addJavaToJDBCTypeMappingTo(java.sql.Timestamp.class, Types.TIMESTAMP, mappings);
-
- // arrays
- addJavaToJDBCTypeMappingTo(byte[].class, Types.VARBINARY, mappings);
- addJavaToJDBCTypeMappingTo(java.lang.Byte[].class, Types.VARBINARY, mappings);
- }
-
- private static void addJavaToJDBCTypeMappingTo(Class<?> javaClass, int jdbcTypeCode, HashMap<String, JavaToJDBCTypeMapping> mappings) {
- // check for duplicates
- Object prev = mappings.put(javaClass.getName(), buildJavaToJDBCTypeMapping(javaClass, jdbcTypeCode));
- if (prev != null) {
- throw new IllegalArgumentException("duplicate Java class: " + ((JavaToJDBCTypeMapping) prev).getJavaType().declaration());
- }
- }
-
- private static JavaToJDBCTypeMapping buildJavaToJDBCTypeMapping(Class<?> javaClass, int jdbcTypeCode) {
- return new JavaToJDBCTypeMapping(new SimpleJavaType(javaClass), JDBCType.type(jdbcTypeCode));
- }
-
-
- // ********** constructor **********
-
- /**
- * Suppress default constructor, ensuring non-instantiability.
- */
- private JDBCTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-
- // ********** member classes **********
-
- /**
- * JDBC => Java
- */
- private static class JDBCToJavaTypeMapping {
- private final JDBCType jdbcType;
- private final JavaType javaType;
-
- JDBCToJavaTypeMapping(JDBCType jdbcType, JavaType javaType) {
- super();
- this.jdbcType = jdbcType;
- this.javaType = javaType;
- }
-
- public JDBCType getJDBCType() {
- return this.jdbcType;
- }
-
- public JavaType getJavaType() {
- return this.javaType;
- }
-
- public boolean maps(int jdbcTypeCode) {
- return this.jdbcType.code() == jdbcTypeCode;
- }
-
- public boolean maps(String jdbcTypeName) {
- return this.jdbcType.name().equals(jdbcTypeName);
- }
-
- public boolean maps(JDBCType type) {
- return this.jdbcType == type;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- this.appendTo(sb);
- return sb.toString();
- }
-
- public void appendTo(StringBuilder sb) {
- this.jdbcType.appendTo(sb);
- sb.append(" => ");
- this.javaType.appendDeclarationTo(sb);
- }
-
- }
-
- /**
- * Java => JDBC
- */
- private static class JavaToJDBCTypeMapping {
- private final JavaType javaType;
- private final JDBCType jdbcType;
-
- JavaToJDBCTypeMapping(JavaType javaType, JDBCType jdbcType) {
- super();
- this.javaType = javaType;
- this.jdbcType = jdbcType;
- }
-
- public JavaType getJavaType() {
- return this.javaType;
- }
-
- public JDBCType getJDBCType() {
- return this.jdbcType;
- }
-
- public boolean maps(JavaType jt) {
- return this.javaType.equals(jt);
- }
-
- public boolean maps(String elementTypeName, int arrayDepth) {
- return this.javaType.equals(elementTypeName, arrayDepth);
- }
-
- public boolean maps(String javaClassName) {
- return this.javaType.describes(javaClassName);
- }
-
- public boolean maps(Class<?> javaClass) {
- return this.javaType.describes(javaClass);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- this.appendTo(sb);
- return sb.toString();
- }
-
- public void appendTo(StringBuilder sb) {
- this.javaType.appendDeclarationTo(sb);
- sb.append(" => ");
- this.jdbcType.appendTo(sb);
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java
deleted file mode 100644
index 82ae294c34..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/JDBCType.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.sql.Types;
-import java.text.Collator;
-
-/**
- * Associate the Java constant and the JDBC type name.
- * These are derived from java.sql.Types.
- *
- * @see java.sql.Types
- */
-public final class JDBCType
- implements Comparable<JDBCType>, Cloneable, Serializable
-{
-
- /**
- * the constant name (e.g. VARCHAR)
- */
- private final String name;
-
- /**
- * the JDBC code used by JDBC drivers
- */
- private final int code;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a JDBC type with the specified name and type code.
- * This is private because all the possible JDBC types are built and
- * stored in the static array TYPES.
- * @see #types()
- */
- private JDBCType(String name, int code) {
- super();
- this.name = name;
- this.code = code;
- }
-
-
- // ********** accessors **********
-
- /**
- * Return the name of the type, as defined in java.sql.Types.
- */
- public String name() {
- return this.name;
- }
-
-
- /**
- * Return the type code, as defined in java.sql.Types.
- */
- public int code() {
- return this.code;
- }
-
-
- // ********** printing and displaying **********
-
- public void appendTo(StringBuilder sb) {
- sb.append(this.name);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(ClassTools.shortClassNameForObject(this));
- sb.append('(');
- this.appendTo(sb);
- sb.append(')');
- return sb.toString();
- }
-
- @Override
- public JDBCType clone() {
- try {
- return (JDBCType) super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- public int compareTo(JDBCType type) {
- return Collator.getInstance().compare(this.name, type.name);
- }
-
-
- // ********** static stuff **********
-
- /**
- * all the JDBC type defined in java.sql.Types
- */
- private static JDBCType[] TYPES; // pseudo 'final' - lazy-initialized
-
-
- public synchronized static JDBCType[] types() {
- if (TYPES == null) {
- TYPES = buildTypes();
- }
- return TYPES;
- }
-
- /**
- * Return the JDBC type for the specified type code (e.g. Types.VARCHAR).
- * @see java.sql.Types
- */
- public static JDBCType type(int code) {
- JDBCType[] types = types();
- for (int i = types.length; i-- > 0; ) {
- if (types[i].code() == code) {
- return types[i];
- }
- }
- throw new IllegalArgumentException("invalid JDBC type code: " + code);
- }
-
- /**
- * Return the JDBC type for the specified type name (e.g. "VARCHAR").
- * @see java.sql.Types
- */
- public static JDBCType type(String name) {
- JDBCType[] types = types();
- for (int i = types.length; i-- > 0; ) {
- if (types[i].name().equals(name)) {
- return types[i];
- }
- }
- throw new IllegalArgumentException("invalid JDBC type name: " + name);
- }
-
- /**
- * build up the JDBC types via reflection
- * @see java.sql.Types
- */
- private static JDBCType[] buildTypes() {
- Field[] fields = Types.class.getDeclaredFields();
- int len = fields.length;
- JDBCType[] types = new JDBCType[len];
- for (int i = len; i-- > 0; ) {
- String name = fields[i].getName();
- int code;
- try {
- code = ((Integer) fields[i].get(null)).intValue();
- } catch (IllegalAccessException ex) {
- throw new RuntimeException(ex); // shouldn't happen...
- }
- types[i] = new JDBCType(name, code);
- }
- return types;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ListenerList.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ListenerList.java
deleted file mode 100644
index a7749bd731..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ListenerList.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.lang.reflect.Array;
-import java.util.Arrays;
-import java.util.EventListener;
-
-/**
- * Maintain a thread-safe list of listeners that does not allow duplicates.
- */
-public class ListenerList<L extends EventListener>
- implements Serializable
-{
- private transient volatile L[] listeners;
-
- private static final long serialVersionUID = 1L;
-
-
- public ListenerList(Class<L> listenerClass) {
- super();
- this.listeners = this.buildEmptyArray(listenerClass);
- }
-
- @SuppressWarnings("unchecked")
- private L[] buildEmptyArray(Class<L> listenerClass) {
- return (L[]) Array.newInstance(listenerClass, 0);
- }
-
- public L[] getListeners() {
- return this.listeners;
- }
-
- public int size() {
- return this.listeners.length;
- }
-
- public boolean isEmpty() {
- return this.listeners.length == 0;
- }
-
- public synchronized void add(L listener) {
- if (listener == null) {
- throw new NullPointerException();
- }
- if (CollectionTools.contains(this.listeners, listener)) {
- return;//throw new IllegalArgumentException("duplicate listener: " + listener); //$NON-NLS-1$
- }
- this.listeners = CollectionTools.add(this.listeners, listener);
- }
-
- public synchronized void remove(L listener) {
- if (listener == null) {
- throw new NullPointerException();
- }
- int index = CollectionTools.indexOf(this.listeners, listener);
- if (index == -1) {
- return;//throw new IllegalArgumentException("unregistered listener: " + listener); //$NON-NLS-1$
- }
- this.listeners = CollectionTools.removeElementAtIndex(this.listeners, index);
- }
-
- public synchronized void clear() {
- this.listeners = CollectionTools.clear(this.listeners);
- }
-
- @Override
- public String toString() {
- return Arrays.toString(this.listeners);
- }
-
-
- // ********** serialization **********
-
- private synchronized void writeObject(ObjectOutputStream s) throws IOException {
- // write out any hidden stuff
- s.defaultWriteObject();
-
- @SuppressWarnings("unchecked")
- Class<L> listenerClass = (Class<L>) this.listeners.getClass().getComponentType();
- s.writeObject(listenerClass);
-
- // only write out serializable listeners
- for (L listener : this.listeners) {
- if (listener instanceof Serializable) {
- s.writeObject(listener);
- }
- }
-
- s.writeObject(null);
- }
-
- @SuppressWarnings("unchecked")
- private synchronized void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
- // read in any hidden stuff
- s.defaultReadObject();
-
- Class<L> listenerClass = (Class<L>) s.readObject();
- this.listeners = this.buildEmptyArray(listenerClass);
- Object o;
- while ((o = s.readObject()) != null) {
- this.add((L) o);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java
deleted file mode 100644
index 570398445e..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NameTools.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.SortedSet;
-import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
-
-/**
- * Various helper methods for generating names.
- */
-public final class NameTools {
-
- /**
- * Given a "root" name and a set of existing names, generate a unique
- * name that is either the "root" name or some variation on the "root"
- * name (e.g. "root2", "root3",...). The names are case-sensitive
- * (i.e. "Root" and "root" are both allowed).
- */
- public static String uniqueNameFor(String rootName, Iterator<String> existingNames) {
- return uniqueNameFor(rootName, CollectionTools.set(existingNames));
- }
-
- /**
- * Given a "root" name and a set of existing names, generate a unique
- * name that is either the "root" name or some variation on the "root"
- * name (e.g. "root2", "root3",...). The names are case-sensitive
- * (i.e. "Root" and "root" are both allowed).
- */
- public static String uniqueNameFor(String rootName, Collection<String> existingNames) {
- return uniqueNameFor(rootName, existingNames, rootName);
- }
-
- /**
- * Given a "root" name and a set of existing names, generate a unique
- * name that is either the "root" name or some variation on the "root"
- * name (e.g. "root2", "root3",...). The names are NOT case-sensitive
- * (i.e. "Root" and "root" are NOT both allowed).
- */
- public static String uniqueNameForIgnoreCase(String rootName, Iterator<String> existingNames) {
- return uniqueNameForIgnoreCase(rootName, CollectionTools.set(existingNames));
- }
-
- /**
- * Given a "root" name and a set of existing names, generate a unique
- * name that is either the "root" name or some variation on the "root"
- * name (e.g. "root2", "root3",...). The names are NOT case-sensitive
- * (i.e. "Root" and "root" are NOT both allowed).
- */
- public static String uniqueNameForIgnoreCase(String rootName, Collection<String> existingNames) {
- return uniqueNameFor(rootName, convertToLowerCase(existingNames), rootName.toLowerCase());
- }
-
- /**
- * use the suffixed "template" name to perform the comparisons, but RETURN
- * the suffixed "root" name; this allows case-insensitive comparisons
- * (i.e. the "template" name has been morphed to the same case as
- * the "existing" names, while the "root" name has not, but the "root" name
- * is what the client wants morphed to be unique)
- */
- private static String uniqueNameFor(String rootName, Collection<String> existingNames, String templateName) {
- if ( ! existingNames.contains(templateName)) {
- return rootName;
- }
- String uniqueName = templateName;
- for (int suffix = 2; true; suffix++) {
- if ( ! existingNames.contains(uniqueName + suffix)) {
- return rootName.concat(String.valueOf(suffix));
- }
- }
- }
-
- /**
- * Convert the specified collection of strings to a collection of the same
- * strings converted to lower case.
- */
- private static HashSet<String> convertToLowerCase(Collection<String> strings) {
- HashSet<String> result = new HashSet<String>(strings.size());
- for (String string : strings) {
- result.add(string.toLowerCase());
- }
- return result;
- }
-
- /**
- * Build a fully-qualified name for the specified database object.
- * Variations:
- * catalog.schema.name
- * catalog..name
- * schema.name
- * name
- */
- public static String buildQualifiedDatabaseObjectName(String catalog, String schema, String name) {
- if (name == null) {
- return null;
- }
- if ((catalog == null) && (schema == null)) {
- return name;
- }
-
- StringBuilder sb = new StringBuilder(100);
- if (catalog != null) {
- sb.append(catalog);
- sb.append('.');
- }
- if (schema != null) {
- sb.append(schema);
- }
- sb.append('.');
- sb.append(name);
- return sb.toString();
- }
-
- /**
- * The set of reserved words in the Java programming language.
- * These words cannot be used as identifiers (i.e. names).
- * http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
- */
- @SuppressWarnings("nls")
- public static final String[] JAVA_RESERVED_WORDS = new String[] {
- "abstract",
- "assert", // jdk 1.4
- "boolean",
- "break",
- "byte",
- "case",
- "catch",
- "char",
- "class",
- "const", // unused
- "continue",
- "default",
- "do",
- "double",
- "else",
- "enum", // jdk 1.5
- "extends",
- "false",
- "final",
- "finally",
- "float",
- "for",
- "goto", // unused
- "if",
- "implements",
- "import",
- "instanceof",
- "int",
- "interface",
- "long",
- "native",
- "new",
- "null",
- "package",
- "private",
- "protected",
- "public",
- "return",
- "short",
- "static",
- "strictfp", // jdk 1.2
- "super",
- "switch",
- "synchronized",
- "this",
- "throw",
- "throws",
- "transient",
- "true",
- "try",
- "void",
- "volatile",
- "while"
- };
-
- /**
- * The set of reserved words in the Java programming language.
- * These words cannot be used as identifiers (i.e. names).
- * http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
- */
- public static final SortedSet<String> JAVA_RESERVED_WORDS_SET =
- Collections.unmodifiableSortedSet(CollectionTools.sortedSet(JAVA_RESERVED_WORDS));
-
- /**
- * Return the set of Java programming language reserved words.
- * These words cannot be used as identifiers (i.e. names).
- * http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
- */
- public static Iterator<String> javaReservedWords() {
- return new ArrayIterator<String>(JAVA_RESERVED_WORDS);
- }
-
- /**
- * Return whether the specified string consists of Java identifier
- * characters (but may be a reserved word).
- */
- public static boolean stringConsistsOfJavaIdentifierCharacters(String string) {
- if (string.length() == 0) {
- return false;
- }
- return stringConsistsOfJavaIdentifierCharacters_(string.toCharArray());
- }
-
- /**
- * Return whether the specified string consists of Java identifier
- * characters (but may be a reserved word).
- */
- public static boolean stringConsistsOfJavaIdentifierCharacters(char[] string) {
- if (string.length == 0) {
- return false;
- }
- return stringConsistsOfJavaIdentifierCharacters_(string);
- }
-
- /**
- * The specified string must not be empty.
- */
- private static boolean stringConsistsOfJavaIdentifierCharacters_(char[] string) {
- if ( ! Character.isJavaIdentifierStart(string[0])) {
- return false;
- }
- for (int i = string.length; i-- > 1; ) { // NB: end with 1
- if ( ! Character.isJavaIdentifierPart(string[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified string is a valid Java identifier.
- */
- public static boolean stringIsLegalJavaIdentifier(String string) {
- return stringConsistsOfJavaIdentifierCharacters(string)
- && ! JAVA_RESERVED_WORDS_SET.contains(string);
- }
-
- /**
- * Return whether the specified string is a valid Java identifier.
- */
- public static boolean stringIsLegalJavaIdentifier(char[] string) {
- return stringConsistsOfJavaIdentifierCharacters(string)
- && ! JAVA_RESERVED_WORDS_SET.contains(new String(string));
- }
-
- /**
- * Convert the specified string to a valid Java identifier
- * by substituting an underscore '_' for any invalid characters
- * in the string and appending an underscore '_' to the string if
- * it is a Java reserved word.
- */
- public static String convertToJavaIdentifier(String string) {
- return convertToJavaIdentifier(string, '_');
- }
-
- /**
- * Convert the specified string to a valid Java identifier
- * by substituting the specified character for any invalid characters
- * in the string and, if necessary, appending the specified character
- * to the string until it is not a Java reserved word.
- */
- public static String convertToJavaIdentifier(String string, char c) {
- if (string.length() == 0) {
- return string;
- }
- if (JAVA_RESERVED_WORDS_SET.contains(string)) {
- // a reserved word is a valid identifier, we just need to tweak it a bit
- checkCharIsJavaIdentifierPart(c);
- return convertToJavaIdentifier(string + c, c);
- }
- char[] array = string.toCharArray();
- return convertToJavaIdentifier_(array, c) ? new String(array) : string;
- }
-
- /**
- * Convert the specified string to a valid Java identifier
- * by substituting an underscore '_' for any invalid characters
- * in the string and appending an underscore '_' to the string if
- * it is a Java reserved word.
- */
- public static char[] convertToJavaIdentifier(char[] string) {
- return convertToJavaIdentifier(string, '_');
- }
-
- /**
- * Convert the specified string to a valid Java identifier
- * by substituting the specified character for any invalid characters
- * in the string and, if necessary, appending the specified character
- * to the string until it is not a Java reserved word.
- */
- public static char[] convertToJavaIdentifier(char[] string, char c) {
- if (string.length == 0) {
- return string;
- }
- if (JAVA_RESERVED_WORDS_SET.contains(new String(string))) {
- // a reserved word is a valid identifier, we just need to tweak it a bit
- checkCharIsJavaIdentifierPart(c);
- return convertToJavaIdentifier(CollectionTools.add(string, c), c);
- }
- convertToJavaIdentifier_(string, c);
- return string;
- }
-
- /**
- * The specified string must not be empty.
- * Return whether the string was modified.
- */
- private static boolean convertToJavaIdentifier_(char[] string, char c) {
- boolean mod = false;
- if ( ! Character.isJavaIdentifierStart(string[0])) {
- checkCharIsJavaIdentifierStart(c);
- string[0] = c;
- mod = true;
- }
- checkCharIsJavaIdentifierPart(c);
- for (int i = string.length; i-- > 1; ) { // NB: end with 1
- if ( ! Character.isJavaIdentifierPart(string[i])) {
- string[i] = c;
- mod = true;
- }
- }
- return mod;
- }
-
- private static void checkCharIsJavaIdentifierStart(char c) {
- if ( ! Character.isJavaIdentifierStart(c)) {
- throw new IllegalArgumentException("invalid Java identifier start char: '" + c + '\''); //$NON-NLS-1$
- }
- }
-
- private static void checkCharIsJavaIdentifierPart(char c) {
- if ( ! Character.isJavaIdentifierPart(c)) {
- throw new IllegalArgumentException("invalid Java identifier part char: '" + c + '\''); //$NON-NLS-1$
- }
- }
-
-
- // ********** constructor **********
-
- /**
- * Suppress default constructor, ensuring non-instantiability.
- */
- private NameTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NullList.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NullList.java
deleted file mode 100644
index 9c9b4eaafd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/NullList.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator;
-
-/**
- * A "null" list is a bit different from an "empty" list: it allows clients to
- * add/remove elements to/from it but never changes. This is useful
- * for passing to methods that require a "collecting parameter" but the
- * client will ignore the resulting "collection".
- *
- * NB: We return 'null' from the following methods (as opposed to throwing
- * an exception):
- * get(int) : E
- * remove(int) : E
- * set(int, E) : E
- */
-public final class NullList<E> implements List<E> {
-
- // singleton
- @SuppressWarnings("unchecked")
- private static final NullList INSTANCE = new NullList();
-
- /**
- * Return the singleton.
- */
- @SuppressWarnings("unchecked")
- public static <E> List<E> instance() {
- return INSTANCE;
- }
-
- /**
- * Ensure single instance.
- */
- private NullList() {
- super();
- }
-
- public boolean add(E o) {
- return false; // the list did not change
- }
-
- public void add(int index, E element) {
- // ignore
- }
-
- public boolean addAll(Collection<? extends E> c) {
- return false; // the list did not change
- }
-
- public boolean addAll(int index, Collection<? extends E> c) {
- return false; // the list did not change
- }
-
- public void clear() {
- // ignore
- }
-
- public boolean contains(Object o) {
- return false;
- }
-
- public boolean containsAll(Collection<?> c) {
- return c.isEmpty();
- }
-
- public E get(int index) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0");
- }
-
- public int indexOf(Object o) {
- return -1;
- }
-
- public boolean isEmpty() {
- return true;
- }
-
- public Iterator<E> iterator() {
- return EmptyIterator.instance();
- }
-
- public int lastIndexOf(Object o) {
- return -1;
- }
-
- public ListIterator<E> listIterator() {
- return EmptyListIterator.instance();
- }
-
- public ListIterator<E> listIterator(int index) {
- return EmptyListIterator.instance();
- }
-
- public boolean remove(Object o) {
- return false; // the list did not change
- }
-
- public E remove(int index) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0");
- }
-
- public boolean removeAll(Collection<?> c) {
- return false; // the list did not change
- }
-
- public boolean retainAll(Collection<?> c) {
- return false; // the list did not change
- }
-
- public E set(int index, E element) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0");
- }
-
- public int size() {
- return 0;
- }
-
- public List<E> subList(int fromIndex, int toIndex) {
- return this;
- }
-
- private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
- public Object[] toArray() {
- return EMPTY_OBJECT_ARRAY;
- }
-
- public <T> T[] toArray(T[] a) {
- return a;
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Range.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Range.java
deleted file mode 100644
index 176918d635..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Range.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-
-/**
- * This simple container class simply puts a bit of semantics
- * around a pair of numbers.
- */
-public class Range
- implements Cloneable, Serializable
-{
- /** The starting index of the range. */
- public final int start;
-
- /** The ending index of the range. */
- public final int end;
-
- /**
- * The size can be negative if the ending index
- * is less than the starting index.
- */
- public final int size;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct with the specified start and end,
- * both of which are immutable.
- */
- public Range(int start, int end) {
- super();
- this.start = start;
- this.end = end;
- this.size = end - start + 1;
- }
-
- /**
- * Return whether the range includes the specified
- * index.
- */
- public boolean includes(int index) {
- return (this.start <= index) && (index <= this.end);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if ( ! (o instanceof Range)) {
- return false;
- }
- Range otherRange = (Range) o;
- return (this.start == otherRange.start)
- && (this.end == otherRange.end);
- }
-
- @Override
- public int hashCode() {
- return this.start ^ this.end;
- }
-
- @Override
- public Range clone() {
- try {
- return (Range) super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- @Override
- public String toString() {
- return '[' + this.start + ", " + this.end + ']'; //$NON-NLS-1$
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java
deleted file mode 100644
index 10c01f80f0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ReverseComparator.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.Comparator;
-
-/**
- * This comparator will reverse the order of the specified comparator.
- * If the comparator is null, the natural ordering of the objects will be used.
- */
-public class ReverseComparator<E extends Comparable<? super E>>
- implements Comparator<E>, Serializable
-{
- private final Comparator<E> comparator;
-
- public ReverseComparator() {
- this(null);
- }
-
- public ReverseComparator(Comparator<E> comparator) {
- super();
- this.comparator = comparator;
- }
-
- public int compare(E e1, E e2) {
- return (this.comparator == null) ?
- e2.compareTo(e1)
- :
- this.comparator.compare(e2, e1);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleAssociation.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleAssociation.java
deleted file mode 100644
index 7c9b0a7401..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleAssociation.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-
-/**
- * Straightforward implementation of Association.
- */
-public class SimpleAssociation<K, V>
- extends AbstractAssociation<K, V>
- implements Cloneable, Serializable
-{
- private final K key;
- private V value;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct an association with the specified key
- * and a null value.
- */
- public SimpleAssociation(K key) {
- super();
- this.key = key;
- }
-
- /**
- * Construct an association with the specified key and value.
- */
- public SimpleAssociation(K key, V value) {
- this(key);
- this.value = value;
- }
-
-
- public K key() {
- return this.key;
- }
-
- public synchronized V value() {
- return this.value;
- }
-
- public synchronized V setValue(V value) {
- V old = this.value;
- this.value = value;
- return old;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public synchronized SimpleAssociation<K, V> clone() {
- try {
- return (SimpleAssociation<K, V>) super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleFilter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleFilter.java
deleted file mode 100644
index 80e21f939b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleFilter.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import org.eclipse.jpt.utility.Filter;
-
-/**
- * Simple, abstract implementation of <code>Filter</code>
- * that holds on to a criterion object that can be used in the
- * <code>accept(Object)</code> or <code>reject(Object)</code>
- * methods. Subclasses can override either of these methods,
- * depending on which is easier to implement. Note that at least
- * one of these methods <em>must</em> be overridden or
- * an infinite loop will occur. If both of them are overridden,
- * only the <code>accept(Object)</code> method will be used.
- * <p>
- * Simplifies the implementation of straightforward inner classes.
- * Here is an example of a filter that can be used by a
- * <code>FilteringIterator</code> to return only those strings
- * in the nested iterator start with "prefix":
- * <pre>
- * Filter<String> filter = new SimpleFilter<String>("prefix") {
- * public boolean accept(String o) {
- * return o.startsWith((String) criterion);
- * }
- * };
- * </pre>
- */
-public abstract class SimpleFilter<T, S>
- implements Filter<T>, Cloneable, Serializable
-{
- protected final S criterion;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * More useful constructor. The specified criterion can
- * be used by a subclass to "accept" or "reject" objects.
- */
- protected SimpleFilter(S criterion) {
- super();
- this.criterion = criterion;
- }
-
- /**
- * Construct a simple filter with a null criterion
- */
- protected SimpleFilter() {
- this(null);
- }
-
- /**
- * Return whether the the specified object should be "rejected".
- * The semantics of "rejected" is determined by the client.
- */
- protected boolean reject(T o) {
- return ! this.accept(o);
- }
-
- /**
- * Return whether the the specified object should be "accepted".
- * The semantics of "accepted" is determined by the client.
- */
- public boolean accept(T o) {
- return ! this.reject(o);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public SimpleFilter<T, S> clone() {
- try {
- return (SimpleFilter<T, S>) super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if ( ! (o instanceof SimpleFilter)) {
- return false;
- }
- SimpleFilter<?, ?> other = (SimpleFilter<?, ?>) o;
- return (this.criterion == null) ?
- (other.criterion == null) : this.criterion.equals(other.criterion);
- }
-
- @Override
- public int hashCode() {
- return (this.criterion == null) ? 0 : this.criterion.hashCode();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.criterion);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java
deleted file mode 100644
index ace5b103ab..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.text.Collator;
-import org.eclipse.jpt.utility.JavaType;
-
-/**
- * Straightforward implementation of the JavaType interface.
- */
-public final class SimpleJavaType
- implements JavaType, Cloneable, Serializable
-{
-
- /**
- * store the type as a name, so we can reference classes
- * that are not loaded
- */
- private final String elementTypeName;
-
- /**
- * non-array types have an array depth of zero
- */
- private final int arrayDepth;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a Java type with the specified element type and array depth.
- */
- public SimpleJavaType(String elementTypeName, int arrayDepth) {
- super();
- if ((elementTypeName == null) || (elementTypeName.length() == 0)) {
- throw new IllegalArgumentException("The element type name is required.");
- }
- if (ClassTools.arrayDepthForClassNamed(elementTypeName) != 0) { // e.g. "[Ljava.lang.Object;"
- throw new IllegalArgumentException("The element type must not be an array: " + elementTypeName + '.');
- }
- if (arrayDepth < 0) {
- throw new IllegalArgumentException("The array depth must be greater than or equal to zero: " + arrayDepth + '.');
- }
- if (elementTypeName.equals(void.class.getName()) && (arrayDepth != 0)) {
- throw new IllegalArgumentException("'void' must have an array depth of zero: " + arrayDepth + '.');
- }
- this.elementTypeName = elementTypeName;
- this.arrayDepth = arrayDepth;
- }
-
- /**
- * Construct a Java type for the specified class.
- * The class name can be in one of the following forms:
- * java.lang.Object
- * int
- * java.util.Map$Entry
- * [Ljava.lang.Object;
- * [I
- * [Ljava.util.Map$Entry;
- */
- public SimpleJavaType(String javaClassName) {
- this(ClassTools.elementTypeNameForClassNamed(javaClassName), ClassTools.arrayDepthForClassNamed(javaClassName));
- }
-
- /**
- * Construct a Java type for the specified class.
- */
- public SimpleJavaType(Class<?> javaClass) {
- this(javaClass.getName());
- }
-
-
- // ********** accessors **********
-
- public String getElementTypeName() {
- return this.elementTypeName;
- }
-
- public int getArrayDepth() {
- return this.arrayDepth;
- }
-
-
- // ********** queries **********
-
- public boolean isArray() {
- return this.arrayDepth > 0;
- }
-
- public boolean isPrimitive() {
- return (this.arrayDepth == 0) && ClassTools.classNamedIsPrimitive(this.elementTypeName);
- }
-
- public boolean isPrimitiveWrapper() {
- return (this.arrayDepth == 0) && ClassTools.classNamedIsPrimitiveWrapperClass(this.elementTypeName);
- }
-
- public boolean isVariablePrimitive() {
- return (this.arrayDepth == 0) && ClassTools.classNamedIsVariablePrimitive(this.elementTypeName);
- }
-
- public boolean isVariablePrimitiveWrapper() {
- return (this.arrayDepth == 0) && ClassTools.classNamedIsVariablePrimitiveWrapperClass(this.elementTypeName);
- }
-
- public Class<?> getJavaClass() throws ClassNotFoundException {
- return ClassTools.classForTypeDeclaration(this.elementTypeName, this.arrayDepth);
- }
-
- public String getJavaClassName() {
- return ClassTools.classNameForTypeDeclaration(this.elementTypeName, this.arrayDepth);
- }
-
-
- // ********** comparison **********
-
- public boolean equals(String otherElementTypeName, int otherArrayDepth) {
- return (this.arrayDepth == otherArrayDepth)
- && this.elementTypeName.equals(otherElementTypeName);
- }
-
- public boolean describes(String className) {
- return this.equals(ClassTools.elementTypeNameForClassNamed(className), ClassTools.arrayDepthForClassNamed(className));
- }
-
- public boolean describes(Class<?> javaClass) {
- return this.describes(javaClass.getName());
- }
-
- public boolean equals(JavaType other) {
- return this.equals(other.getElementTypeName(), other.getArrayDepth());
- }
-
- @Override
- public boolean equals(Object o) {
- return (this == o) ? true : (o instanceof JavaType) ? this.equals((JavaType) o) : false;
- }
-
- @Override
- public int hashCode() {
- return this.elementTypeName.hashCode() ^ this.arrayDepth;
- }
-
- public int compareTo(JavaType jt) {
- int x = Collator.getInstance().compare(this.elementTypeName, jt.getElementTypeName());
- return (x != 0) ? x : (this.arrayDepth - jt.getArrayDepth());
- }
-
-
- // ********** printing and displaying **********
-
- /**
- * Return the version of the type's name that can be used in source code:
- * "[[J" => "long[][]"
- * "java.util.Map$Entry" => "java.util.Map.Entry"
- */
- public String declaration() {
- if (this.arrayDepth == 0) {
- return this.elementTypeNameDeclaration();
- }
- StringBuilder sb = new StringBuilder(this.elementTypeName.length() + (2 * this.arrayDepth));
- this.appendDeclarationTo(sb);
- return sb.toString();
- }
-
- /**
- * Append the version of the type's name that can be used in source code:
- * "[[J" => "long[][]"
- * "java.util.Map$Entry" => "java.util.Map.Entry"
- */
- public void appendDeclarationTo(StringBuilder sb) {
- sb.append(this.elementTypeNameDeclaration());
- for (int i = this.arrayDepth; i-- > 0; ) {
- sb.append("[]");
- }
- }
-
- /**
- * Print the version of the type's name that can be used in source code:
- * "[[J" => "long[][]"
- * "java.util.Map$Entry" => "java.util.Map.Entry"
- */
- public void printDeclarationOn(PrintWriter pw) {
- pw.print(this.elementTypeNameDeclaration());
- for (int i = this.arrayDepth; i-- > 0; ) {
- pw.print("[]");
- }
- }
-
- /**
- * The '$' version of the name is used in Class.forName(String),
- * but the '.' verions of the name is used in source code.
- * Very irritating....
- */
- private String elementTypeNameDeclaration() {
- return this.elementTypeName.replace('$', '.');
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(ClassTools.shortClassNameForObject(this));
- sb.append('(');
- this.appendDeclarationTo(sb);
- sb.append(')');
- return sb.toString();
- }
-
-
- // ********** cloning **********
-
- @Override
- public Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java
deleted file mode 100644
index 7996919350..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.text.Collator;
-import java.util.Arrays;
-import org.eclipse.jpt.utility.JavaType;
-import org.eclipse.jpt.utility.MethodSignature;
-
-/**
- * Straightforward implementation of the MethodSignature interface.
- */
-public final class SimpleMethodSignature
- implements MethodSignature, Cloneable, Serializable
-{
- private final String name;
-
- /**
- * store the parameter types as names, so we can reference classes
- * that are not loaded
- */
- private final JavaType[] parameterTypes;
-
- private static final long serialVersionUID = 1L;
-
- public static final JavaType[] EMPTY_PARAMETER_TYPES = new JavaType[0];
-
-
- // ********** constructors **********
-
- /**
- * Construct a method signature with the specified name and
- * no parameter types.
- */
- public SimpleMethodSignature(String name) {
- this(name, EMPTY_PARAMETER_TYPES);
- }
-
- /**
- * Construct a method signature with the specified name and parameter
- * types.
- */
- public SimpleMethodSignature(String name, JavaType... parameterTypes) {
- super();
- if ((name == null) || (name.length() == 0)) {
- throw new IllegalArgumentException("The name is required.");
- }
- if (parameterTypes == null) {
- throw new IllegalArgumentException("The parameter types are required.");
- }
- checkParameterTypes(parameterTypes);
- this.name = name;
- this.parameterTypes = parameterTypes;
- }
-
- private static void checkParameterTypes(JavaType[] parameterTypes) {
- for (int i = 0; i < parameterTypes.length; i++) {
- if (parameterTypes[i] == null) {
- throw new IllegalArgumentException("Missing parameter type: " + i);
- }
- if (parameterTypes[i].getElementTypeName().equals(void.class.getName())) {
- throw new IllegalArgumentException("A parameter type of 'void' is not allowed: " + i);
- }
- }
- }
-
- /**
- * Construct a method signature with the specified name and parameter
- * types.
- */
- public SimpleMethodSignature(String name, String... parameterTypeNames) {
- this(name, buildParameterTypes(parameterTypeNames));
- }
-
- private static JavaType[] buildParameterTypes(String[] parameterTypeNames) {
- if (parameterTypeNames == null) {
- throw new IllegalArgumentException("The parameter type names are required.");
- }
- JavaType[] parameterTypes = new JavaType[parameterTypeNames.length];
- for (int i = 0; i < parameterTypeNames.length; i++) {
- if (parameterTypeNames[i] == null) {
- throw new IllegalArgumentException("Missing parameter type name: " + i);
- }
- parameterTypes[i] = new SimpleJavaType(parameterTypeNames[i]);
- }
- return parameterTypes;
- }
-
- /**
- * Construct a method signature with the specified name and parameter
- * types.
- */
- public SimpleMethodSignature(String name, Class<?>... parameterJavaClasses) {
- this(name, buildParameterTypeNames(parameterJavaClasses));
- }
-
- private static String[] buildParameterTypeNames(Class<?>[] parameterJavaClasses) {
- if (parameterJavaClasses == null) {
- throw new IllegalArgumentException("The parameter Java classes are required.");
- }
- String[] parameterTypeNames = new String[parameterJavaClasses.length];
- for (int i = 0; i < parameterJavaClasses.length; i++) {
- if (parameterJavaClasses[i] == null) {
- throw new IllegalArgumentException("Missing parameter Java class: " + i);
- }
- parameterTypeNames[i] = parameterJavaClasses[i].getName();
- }
- return parameterTypeNames;
- }
-
- /**
- * Construct a method signature for the specified Java method.
- */
- public SimpleMethodSignature(Method method) {
- this(method.getName(), method.getParameterTypes());
- }
-
-
- // ********** accessors **********
-
- public String getName() {
- return this.name;
- }
-
- public JavaType[] getParameterTypes() {
- return this.parameterTypes;
- }
-
-
- // ********** comparison **********
-
- public boolean equals(String otherName, JavaType[] otherParameterTypes) {
- return this.name.equals(otherName)
- && Arrays.equals(this.parameterTypes, otherParameterTypes);
- }
-
- public boolean equals(MethodSignature other) {
- return this.equals(other.getName(), other.getParameterTypes());
- }
-
- @Override
- public boolean equals(Object o) {
- return (this == o) ? true : (o instanceof MethodSignature) ? this.equals((MethodSignature) o) : false;
- }
-
- @Override
- public int hashCode() {
- return this.name.hashCode() ^ Arrays.hashCode(this.parameterTypes);
- }
-
- public int compareTo(MethodSignature ms) {
- int compare = Collator.getInstance().compare(this.name, ms.getName());
- return (compare != 0) ? compare : this.compareParameterTypes(ms.getParameterTypes());
- }
-
- private int compareParameterTypes(JavaType[] otherParameterTypes) {
- int len1 = this.parameterTypes.length;
- int len2 = otherParameterTypes.length;
- int min = Math.min(len1, len2);
- for (int i = 0; i < min; i++) {
- int compare = this.parameterTypes[i].compareTo(otherParameterTypes[i]);
- if (compare != 0) {
- return compare;
- }
- }
- return (len1 == len2) ? 0 : (len1 < len2) ? -1 : 1;
- }
-
-
- // ********** printing and displaying **********
-
- public String getSignature() {
- StringBuilder sb = new StringBuilder(200);
- this.appendSignatureTo(sb);
- return sb.toString();
- }
-
- public void appendSignatureTo(StringBuilder sb) {
- sb.append(this.name);
- sb.append('(');
- for (int i = 0; i < this.parameterTypes.length; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- this.parameterTypes[i].appendDeclarationTo(sb);
- }
- sb.append(')');
- }
-
- public void printSignatureOn(PrintWriter pw) {
- pw.print(this.name);
- pw.print('(');
- for (int i = 0; i < this.parameterTypes.length; i++) {
- if (i != 0) {
- pw.print(", ");
- }
- this.parameterTypes[i].printDeclarationOn(pw);
- }
- pw.print(')');
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(200);
- sb.append(ClassTools.shortClassNameForObject(this));
- sb.append('(');
- this.appendSignatureTo(sb);
- sb.append(')');
- return sb.toString();
- }
-
-
- // ********** cloning **********
-
- @Override
- public Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
deleted file mode 100644
index f183943d9a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.EmptyStackException;
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-
-/**
- * Straightforward implementation of the Stack interface.
- */
-public class SimpleStack<E>
- implements Stack<E>, Cloneable, Serializable
-{
- private LinkedList<E> elements;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct an empty stack.
- */
- public SimpleStack() {
- super();
- this.elements = new LinkedList<E>();
- }
-
- /**
- * Construct a stack containing the elements of the specified
- * collection. The stack will pop its elements in reverse of the
- * order they are returned by the collection's iterator (i.e. the
- * last element returned by the collection's iterator will be the
- * first element returned by #pop()).
- */
- public SimpleStack(Collection<? extends E> c) {
- super();
- this.elements = new LinkedList<E>(c);
- }
-
-
- // ********** Stack implementation **********
-
- public void push(E o) {
- this.elements.addLast(o);
- }
-
- public E pop() {
- try {
- return this.elements.removeLast();
- } catch (NoSuchElementException ex) {
- throw new EmptyStackException();
- }
- }
-
- public E peek() {
- try {
- return this.elements.getLast();
- } catch (NoSuchElementException ex) {
- throw new EmptyStackException();
- }
- }
-
- public boolean isEmpty() {
- return this.elements.isEmpty();
- }
-
-
- // ********** Cloneable implementation **********
-
- @Override
- public SimpleStack<E> clone() {
- try {
- @SuppressWarnings("unchecked")
- SimpleStack<E> clone = (SimpleStack<E>) super.clone();
- @SuppressWarnings("unchecked")
- LinkedList<E> ll = (LinkedList<E>) this.elements.clone();
- clone.elements = ll;
- return clone;
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java
deleted file mode 100644
index 5631b623c8..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStringMatcher.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.regex.Pattern;
-import org.eclipse.jpt.utility.Filter;
-
-// TODO the regex code is not very fast - we could probably do better,
-// hand-coding the matching algorithm (eclipse StringMatcher?)
-/**
- * This class implements a simple string-matching algorithm that is a little
- * more user-friendly than standard regular expressions. Instantiate a
- * string matcher with a filter pattern and then you can use the matcher
- * to determine whether another string (or object) matches the pattern.
- * You can also specify whether the matching should be case-sensitive.
- *
- * The pattern can contain two "meta-characters":
- * '*' will match any set of zero or more characters
- * '?' will match any single character
- *
- * Subclasses can override #prefix() and/or #suffix() to change what
- * strings are prepended or appended to the original pattern string.
- * This can offer a slight performance improvement over concatenating
- * strings before calling #setPatternString(String).
- * By default, a '*' is appended to every string.
- *
- * This class also uses the string-matching algorithm to "filter" objects
- * (and, as a result, also implements the Filter interface).
- * A string converter is used to determine what string aspect of the
- * object is compared to the pattern. By default the string returned
- * by the object's #toString() method is passed to the pattern matcher.
- */
-public class SimpleStringMatcher<T>
- implements StringMatcher, Filter<T>, Serializable
-{
-
- /** An adapter that converts the objects into strings to be matched with the pattern. */
- private StringConverter<T> stringConverter;
-
- /** The string used to construct the regular expression pattern. */
- private String patternString;
-
- /** Whether the matcher ignores case - the default is true. */
- private boolean ignoresCase;
-
- /** The regular expression pattern built from the pattern string. */
- private Pattern pattern;
-
- /** A list of the meta-characters we need to escape if found in the pattern string. */
- public static final char[] REG_EX_META_CHARS = { '(', '[', '{', '\\', '^', '$', '|', ')', '?', '*', '+', '.' };
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a string matcher with an pattern that will match
- * any string and ignore case.
- */
- public SimpleStringMatcher() {
- this("*");
- }
-
- /**
- * Construct a string matcher with the specified pattern
- * that will ignore case.
- */
- public SimpleStringMatcher(String patternString) {
- this(patternString, true);
- }
-
- /**
- * Construct a string matcher with the specified pattern that will
- * ignore case as specified.
- */
- public SimpleStringMatcher(String patternString, boolean ignoresCase) {
- super();
- this.patternString = patternString;
- this.ignoresCase = ignoresCase;
- this.initialize();
- }
-
-
- // ********** initialization **********
-
- protected void initialize() {
- this.stringConverter = StringConverter.Default.instance();
- this.rebuildPattern();
- }
-
- /**
- * Given the current pattern string and case-sensitivity setting,
- * re-build the regular expression pattern.
- */
- protected synchronized void rebuildPattern() {
- this.pattern = this.buildPattern();
- }
-
- /**
- * Given the current pattern string and case-sensitivity setting,
- * build and return a regular expression pattern that can be used
- * to match strings.
- */
- protected Pattern buildPattern() {
- int patternFlags = 0x0;
- if (this.ignoresCase) {
- patternFlags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE;
- }
- return Pattern.compile(this.convertToRegEx(this.patternString), patternFlags);
- }
-
-
- // ********** StringMatcher implementation **********
-
- public synchronized void setPatternString(String patternString) {
- this.patternString = patternString;
- this.rebuildPattern();
- }
-
- /**
- * Return whether the specified string matches the pattern.
- */
- public synchronized boolean matches(String string) {
- return this.pattern.matcher(string).matches();
- }
-
-
- // ********** Filter implementation **********
-
- public synchronized boolean accept(T o) {
- return this.matches(this.stringConverter.convertToString(o));
- }
-
-
- // ********** accessors **********
-
- /**
- * Return the string converter used to convert the objects
- * passed to the matcher into strings.
- */
- public synchronized StringConverter<T> stringConverter() {
- return this.stringConverter;
- }
-
- /**
- * Set the string converter used to convert the objects
- * passed to the matcher into strings.
- */
- public synchronized void setStringConverter(StringConverter<T> stringConverter) {
- this.stringConverter = stringConverter;
- }
-
- /**
- * Return the original pattern string.
- */
- public synchronized String patternString() {
- return this.patternString;
- }
-
- /**
- * Return whether the matcher ignores case.
- */
- public synchronized boolean ignoresCase() {
- return this.ignoresCase;
- }
-
- /**
- * Set whether the matcher ignores case.
- */
- public synchronized void setIgnoresCase(boolean ignoresCase) {
- this.ignoresCase = ignoresCase;
- this.rebuildPattern();
- }
-
- /**
- * Return the regular expression pattern.
- */
- public synchronized Pattern pattern() {
- return this.pattern;
- }
-
-
- // ********** other public API **********
-
- /**
- * Return the regular expression corresponding to
- * the original pattern string.
- */
- public synchronized String regularExpression() {
- return this.convertToRegEx(this.patternString);
- }
-
-
- // ********** converting **********
-
- /**
- * Convert the specified string to a regular expression.
- */
- protected String convertToRegEx(String string) {
- StringBuffer sb = new StringBuffer(string.length() + 10);
- this.convertToRegExOn(this.prefix(), sb);
- this.convertToRegExOn(string, sb);
- this.convertToRegExOn(this.suffix(), sb);
- return sb.toString();
- }
-
- /**
- * Return any prefix that should be prepended to the original
- * string. By default, there is no prefix.
- */
- protected String prefix() {
- return "";
- }
-
- /**
- * Return any suffix that should be appended to the original
- * string. Since this class is typically used in UI situation where
- * the user is typing in a pattern used to filter a list, the default
- * suffix is a wildcard character.
- */
- protected String suffix() {
- return "*";
- }
-
- /**
- * Convert the specified string to a regular expression.
- */
- protected void convertToRegExOn(String string, StringBuffer sb) {
- char[] charArray = string.toCharArray();
- int length = charArray.length;
- for (int i = 0; i < length; i++) {
- char c = charArray[i];
- // convert user-friendly meta-chars into regex meta-chars
- if (c == '*') {
- sb.append(".*");
- continue;
- }
- if (c == '?') {
- sb.append('.');
- continue;
- }
- // escape regex meta-chars
- if (CollectionTools.contains(REG_EX_META_CHARS, c)) {
- sb.append('\\');
- }
- sb.append(c);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
deleted file mode 100644
index 93bef64f4b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.EmptyStackException;
-
-/**
- * Interface defining the classic stack behavior,
- * without the backdoors allowed by java.util.Stack.
- * E is the type of elements contained by the Stack.
- */
-public interface Stack<E> {
-
- /**
- * "Push" the specified item on to the top of the stack.
- */
- void push(E o);
-
- /**
- * "Pop" an item from the top of the stack.
- */
- E pop();
-
- /**
- * Return the item on the top of the stack
- * without removing it from the stack.
- */
- E peek();
-
- /**
- * Return whether the stack is empty.
- */
- boolean isEmpty();
-
-
- final class Empty<E> implements Stack<E>, Serializable {
- @SuppressWarnings("unchecked")
- public static final Stack INSTANCE = new Empty();
- @SuppressWarnings("unchecked")
- public static <T> Stack<T> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Empty() {
- super();
- }
- public void push(E o) {
- throw new UnsupportedOperationException();
- }
- public E pop() {
- throw new EmptyStackException();
- }
- public E peek() {
- throw new EmptyStackException();
- }
- public boolean isEmpty() {
- return true;
- }
- private static final long serialVersionUID = 1L;
- private Object readResolve() {
- return INSTANCE;
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringConverter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringConverter.java
deleted file mode 100644
index 556b530862..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringConverter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Used by various "pluggable" classes to transform objects
- * into strings.
- */
-public interface StringConverter<T> {
-
- /**
- * Convert the specified object into a string.
- * The semantics of "convert" is determined by the
- * contract between the client and the server.
- */
- String convertToString(T o);
-
-
- final class Default<S> implements StringConverter<S> {
- @SuppressWarnings("unchecked")
- public static final StringConverter INSTANCE = new Default();
- @SuppressWarnings("unchecked")
- public static <R> StringConverter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Default() {
- super();
- }
- // simply return the object's #toString() result
- public String convertToString(S o) {
- return (o == null) ? null : o.toString();
- }
- @Override
- public String toString() {
- return "StringConverter.Default";
- }
- }
-
- final class Disabled<S> implements StringConverter<S> {
- @SuppressWarnings("unchecked")
- public static final StringConverter INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> StringConverter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public String convertToString(S o) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "StringConverter.Disabled";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java
deleted file mode 100644
index 5f769d7040..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringMatcher.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * This interface defines a simple API for allowing "pluggable"
- * string matchers that can be configured with a pattern string
- * then used to determine what strings match the pattern.
- */
-public interface StringMatcher {
-
- /**
- * Set the pattern string used to determine future
- * matches. The format and semantics of the pattern
- * string are determined by the contract between the
- * client and the server.
- */
- void setPatternString(String patternString);
-
- /**
- * Return whether the specified string matches the
- * established pattern string. The semantics of a match
- * is determined by the contract between the
- * client and the server.
- */
- boolean matches(String string);
-
-
- final class Null implements StringMatcher {
- public static final StringMatcher INSTANCE = new Null();
- public static StringMatcher instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- public void setPatternString(String patternString) {
- // ignore the pattern string
- }
- public boolean matches(String string) {
- // everything is a match
- return true;
- }
- @Override
- public String toString() {
- return "StringMatcher.Null";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java
deleted file mode 100644
index 4fd0a82dac..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StringTools.java
+++ /dev/null
@@ -1,4108 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Arrays;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
-
-/**
- * Convenience methods related to the java.lang.String class.
- *
- * As of jdk 1.5, it's tempting to convert all of these methods to use
- * java.lang.Appendable (instead of StringBuffer, StringBuilder, and Writer);
- * but all the Appendable methods throw java.io.IOException (yech) and we
- * [might?] get a bit better performance invoking methods on classes than
- * we get on interfaces. :-)
- */
-public final class StringTools {
-
- /** carriage return */
- public static final String CR = System.getProperty("line.separator"); //$NON-NLS-1$
-
- /** double quote */
- public static final char QUOTE = '"';
-
- /** parenthesis */
- public static final char OPEN_PARENTHESIS = '(';
- public static final char CLOSE_PARENTHESIS = ')';
-
- /** brackets */
- public static final char OPEN_BRACKET = '[';
- public static final char CLOSE_BRACKET = ']';
-
- /** brackets */
- public static final char OPEN_BRACE = '{';
- public static final char CLOSE_BRACE = '}';
-
- /** brackets */
- public static final char OPEN_CHEVRON = '<';
- public static final char CLOSE_CHEVRON = '>';
-
- /** empty string */
- public static final String EMPTY_STRING = ""; //$NON-NLS-1$
-
- /** empty char array */
- public static final char[] EMPTY_CHAR_ARRAY = new char[0];
-
-
-
- // ********** padding/truncating **********
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#pad(int)
- */
- public static String pad(String string, int length) {
- return pad(string, length, ' ');
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOn(int, Writer)
- */
- public static void padOn(String string, int length, Writer writer) {
- padOn(string, length, ' ', writer);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOn(int, StringBuffer)
- */
- public static void padOn(String string, int length, StringBuffer sb) {
- padOn(string, length, ' ', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOn(int, StringBuilder)
- */
- public static void padOn(String string, int length, StringBuilder sb) {
- padOn(string, length, ' ', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#pad(int, char)
- */
- public static String pad(String string, int length, char c) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- return string;
- }
- return pad_(string, length, c);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOn(int, char, Writer)
- */
- public static void padOn(String string, int length, char c, Writer writer) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else {
- padOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOn(int, char, StringBuffer)
- */
- public static void padOn(String string, int length, char c, StringBuffer sb) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOn(int, char, StringBuilder)
- */
- public static void padOn(String string, int length, char c, StringBuilder sb) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#pad(int)
- */
- public static char[] pad(char[] string, int length) {
- return pad(string, length, ' ');
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOn(int, writer)
- */
- public static void padOn(char[] string, int length, Writer writer) {
- padOn(string, length, ' ', writer);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOn(int, StringBuffer)
- */
- public static void padOn(char[] string, int length, StringBuffer sb) {
- padOn(string, length, ' ', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOn(int, StringBuilder)
- */
- public static void padOn(char[] string, int length, StringBuilder sb) {
- padOn(string, length, ' ', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#pad(int, char)
- */
- public static char[] pad(char[] string, int length, char c) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- return string;
- }
- return pad_(string, length, c);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOn(int, char, Writer)
- */
- public static void padOn(char[] string, int length, char c, Writer writer) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else {
- padOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOn(int, char, StringBuffer)
- */
- public static void padOn(char[] string, int length, char c, StringBuffer sb) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOn(int, char, StringBuilder)
- */
- public static void padOn(char[] string, int length, char c, StringBuilder sb) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncate(int)
- */
- public static String padOrTruncate(String string, int length) {
- return padOrTruncate(string, length, ' ');
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncateOn(int, Writer)
- */
- public static void padOrTruncateOn(String string, int length, Writer writer) {
- padOrTruncateOn(string, length, ' ', writer);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncateOn(int, StringBuffer)
- */
- public static void padOrTruncateOn(String string, int length, StringBuffer sb) {
- padOrTruncateOn(string, length, ' ', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncateOn(int, StringBuilder)
- */
- public static void padOrTruncateOn(String string, int length, StringBuilder sb) {
- padOrTruncateOn(string, length, ' ', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncate(int, char)
- */
- public static String padOrTruncate(String string, int length, char c) {
- int stringLength = string.length();
- if (stringLength == length) {
- return string;
- }
- if (stringLength > length) {
- return string.substring(0, length);
- }
- return pad_(string, length, c);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncateOn(int, char, Writer)
- */
- public static void padOrTruncateOn(String string, int length, char c, Writer writer) {
- int stringLength = string.length();
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else if (stringLength > length) {
- writeStringOn(string.substring(0, length), writer);
- } else {
- padOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncateOn(int, char, StringBuffer)
- */
- public static void padOrTruncateOn(String string, int length, char c, StringBuffer sb) {
- int stringLength = string.length();
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string.substring(0, length));
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncateOn(int, char, StringBuilder)
- */
- public static void padOrTruncateOn(String string, int length, char c, StringBuilder sb) {
- int stringLength = string.length();
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string.substring(0, length));
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncate(int)
- */
- public static char[] padOrTruncate(char[] string, int length) {
- return padOrTruncate(string, length, ' ');
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncateOn(int, Writer)
- */
- public static void padOrTruncateOn(char[] string, int length, Writer writer) {
- padOrTruncateOn(string, length, ' ', writer);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncateOn(int, StringBuffer)
- */
- public static void padOrTruncate(char[] string, int length, StringBuffer sb) {
- padOrTruncateOn(string, length, ' ', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with spaces at the end.
- * String#padOrTruncateOn(int, StringBuilder)
- */
- public static void padOrTruncate(char[] string, int length, StringBuilder sb) {
- padOrTruncateOn(string, length, ' ', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncate(int, char)
- */
- public static char[] padOrTruncate(char[] string, int length, char c) {
- int stringLength = string.length;
- if (stringLength == length) {
- return string;
- }
- if (stringLength > length) {
- char[] result = new char[length];
- System.arraycopy(string, 0, result, 0, length);
- return result;
- }
- return pad_(string, length, c);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncateOn(int, char, Writer)
- */
- public static void padOrTruncateOn(char[] string, int length, char c, Writer writer) {
- int stringLength = string.length;
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else if (stringLength > length) {
- writeStringOn(string, 0, length, writer);
- } else {
- padOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncateOn(int, char, StringBuffer)
- */
- public static void padOrTruncateOn(char[] string, int length, char c, StringBuffer sb) {
- int stringLength = string.length;
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string, 0, length);
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, it is truncated.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the end.
- * String#padOrTruncateOn(int, char, StringBuilder)
- */
- public static void padOrTruncateOn(char[] string, int length, char c, StringBuilder sb) {
- int stringLength = string.length;
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string, 0, length);
- } else {
- padOn_(string, length, c, sb);
- }
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static String pad_(String string, int length, char c) {
- return new String(pad_(string.toCharArray(), length, c));
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void padOn_(String string, int length, char c, Writer writer) {
- writeStringOn(string, writer);
- fill_(string, length, c, writer);
- }
-
- /*
- * Add enough characters to the specified writer to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(String string, int length, char c, Writer writer) {
- fill_(string.length(), length, c, writer);
- }
-
- /*
- * Add enough characters to the specified writer to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(char[] string, int length, char c, Writer writer) {
- fill_(string.length, length, c, writer);
- }
-
- /*
- * Add enough characters to the specified writer to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(int stringLength, int length, char c, Writer writer) {
- writeStringOn(CollectionTools.fill(new char[length - stringLength], c), writer);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void padOn_(String string, int length, char c, StringBuffer sb) {
- sb.append(string);
- fill_(string, length, c, sb);
- }
-
- /*
- * Add enough characters to the specified string buffer to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(String string, int length, char c, StringBuffer sb) {
- fill_(string.length(), length, c, sb);
- }
-
- /*
- * Add enough characters to the specified string buffer to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(char[] string, int length, char c, StringBuffer sb) {
- fill_(string.length, length, c, sb);
- }
-
- /*
- * Add enough characters to the specified string buffer to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(int stringLength, int length, char c, StringBuffer sb) {
- sb.append(CollectionTools.fill(new char[length - stringLength], c));
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void padOn_(String string, int length, char c, StringBuilder sb) {
- sb.append(string);
- fill_(string, length, c, sb);
- }
-
- /*
- * Add enough characters to the specified string builder to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(String string, int length, char c, StringBuilder sb) {
- fill_(string.length(), length, c, sb);
- }
-
- /*
- * Add enough characters to the specified string builder to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(char[] string, int length, char c, StringBuilder sb) {
- fill_(string.length, length, c, sb);
- }
-
- /*
- * Add enough characters to the specified string builder to compensate for
- * the difference between the specified string and specified length.
- */
- private static void fill_(int stringLength, int length, char c, StringBuilder sb) {
- sb.append(CollectionTools.fill(new char[length - stringLength], c));
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static char[] pad_(char[] string, int length, char c) {
- char[] result = new char[length];
- int stringLength = string.length;
- System.arraycopy(string, 0, result, 0, stringLength);
- Arrays.fill(result, stringLength, length, c);
- return result;
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void padOn_(char[] string, int length, char c, Writer writer) {
- writeStringOn(string, writer);
- fill_(string, length, c, writer);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void padOn_(char[] string, int length, char c, StringBuffer sb) {
- sb.append(string);
- fill_(string, length, c, sb);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void padOn_(char[] string, int length, char c, StringBuilder sb) {
- sb.append(string);
- fill_(string, length, c, sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPad(int)
- */
- public static String zeroPad(String string, int length) {
- return frontPad(string, length, '0');
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOn(int, Writer)
- */
- public static void zeroPadOn(String string, int length, Writer writer) {
- frontPadOn(string, length, '0', writer);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOn(int, StringBuffer)
- */
- public static void zeroPadOn(String string, int length, StringBuffer sb) {
- frontPadOn(string, length, '0', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOn(int, StringBuilder)
- */
- public static void zeroPadOn(String string, int length, StringBuilder sb) {
- frontPadOn(string, length, '0', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPad(int, char)
- */
- public static String frontPad(String string, int length, char c) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- return string;
- }
- return frontPad_(string, length, c);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOn(int, char, Writer)
- */
- public static void frontPadOn(String string, int length, char c, Writer writer) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else {
- frontPadOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOn(int, char, StringBuffer)
- */
- public static void frontPadOn(String string, int length, char c, StringBuffer sb) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOn(int, char, StringBuilder)
- */
- public static void frontPadOn(String string, int length, char c, StringBuilder sb) {
- int stringLength = string.length();
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPad(int)
- */
- public static char[] zeroPad(char[] string, int length) {
- return frontPad(string, length, '0');
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOn(int, Writer)
- */
- public static void zeroPadOn(char[] string, int length, Writer writer) {
- frontPadOn(string, length, '0', writer);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOn(int, StringBuffer)
- */
- public static void zeroPadOn(char[] string, int length, StringBuffer sb) {
- frontPadOn(string, length, '0', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOn(int, StringBuilder)
- */
- public static void zeroPadOn(char[] string, int length, StringBuilder sb) {
- frontPadOn(string, length, '0', sb);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPad(int, char)
- */
- public static char[] frontPad(char[] string, int length, char c) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- return string;
- }
- return frontPad_(string, length, c);
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOn(int, char, Writer)
- */
- public static void frontPadOn(char[] string, int length, char c, Writer writer) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else {
- frontPadOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOn(int, char, StringBuffer)
- */
- public static void frontPadOn(char[] string, int length, char c, StringBuffer sb) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, an IllegalArgumentException is thrown.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOn(int, char, StringBuilder)
- */
- public static void frontPadOn(char[] string, int length, char c, StringBuilder sb) {
- int stringLength = string.length;
- if (stringLength > length) {
- throw new IllegalArgumentException("String is too long: " + stringLength + " > " + length); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (stringLength == length) {
- sb.append(string);
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncate(int)
- */
- public static String zeroPadOrTruncate(String string, int length) {
- return frontPadOrTruncate(string, length, '0');
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncateOn(int, Writer)
- */
- public static void zeroPadOrTruncateOn(String string, int length, Writer writer) {
- frontPadOrTruncateOn(string, length, '0', writer);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncateOn(int, StringBuffer)
- */
- public static void zeroPadOrTruncateOn(String string, int length, StringBuffer sb) {
- frontPadOrTruncateOn(string, length, '0', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncateOn(int, StringBuilder)
- */
- public static void zeroPadOrTruncateOn(String string, int length, StringBuilder sb) {
- frontPadOrTruncateOn(string, length, '0', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncate(int, char)
- */
- public static String frontPadOrTruncate(String string, int length, char c) {
- int stringLength = string.length();
- if (stringLength == length) {
- return string;
- }
- if (stringLength > length) {
- return string.substring(stringLength - length);
- }
- return frontPad_(string, length, c);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncateOn(int, char, Writer)
- */
- public static void frontPadOrTruncateOn(String string, int length, char c, Writer writer) {
- int stringLength = string.length();
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else if (stringLength > length) {
- writeStringOn(string.substring(stringLength - length), writer);
- } else {
- frontPadOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncateOn(int, char, StringBuffer)
- */
- public static void frontPadOrTruncateOn(String string, int length, char c, StringBuffer sb) {
- int stringLength = string.length();
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string.substring(stringLength - length));
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncateOn(int, char, StringBuilder)
- */
- public static void frontPadOrTruncateOn(String string, int length, char c, StringBuilder sb) {
- int stringLength = string.length();
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string.substring(stringLength - length));
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncate(int)
- */
- public static char[] zeroPadOrTruncate(char[] string, int length) {
- return frontPadOrTruncate(string, length, '0');
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncateOn(int, Writer)
- */
- public static void zeroPadOrTruncateOn(char[] string, int length, Writer writer) {
- frontPadOrTruncateOn(string, length, '0', writer);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncateOn(int, StringBuffer)
- */
- public static void zeroPadOrTruncateOn(char[] string, int length, StringBuffer sb) {
- frontPadOrTruncateOn(string, length, '0', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with zeros at the front.
- * String#zeroPadOrTruncateOn(int, StringBuilder)
- */
- public static void zeroPadOrTruncateOn(char[] string, int length, StringBuilder sb) {
- frontPadOrTruncateOn(string, length, '0', sb);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncate(int, char)
- */
- public static char[] frontPadOrTruncate(char[] string, int length, char c) {
- int stringLength = string.length;
- if (stringLength == length) {
- return string;
- }
- if (stringLength > length) {
- char[] result = new char[length];
- System.arraycopy(string, stringLength - length, result, 0, length);
- return result;
- }
- return frontPad_(string, length, c);
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncateOn(int, char, Writer)
- */
- public static void frontPadOrTruncateOn(char[] string, int length, char c, Writer writer) {
- int stringLength = string.length;
- if (stringLength == length) {
- writeStringOn(string, writer);
- } else if (stringLength > length) {
- writeStringOn(string, stringLength - length, length, writer);
- } else {
- frontPadOn_(string, length, c, writer);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncateOn(int, char, StringBuffer)
- */
- public static void frontPadOrTruncateOn(char[] string, int length, char c, StringBuffer sb) {
- int stringLength = string.length;
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string, stringLength - length, length);
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /**
- * Pad or truncate the specified string to the specified length.
- * If the string is already the specified length, it is returned unchanged.
- * If it is longer than the specified length, only the last part of the string is returned.
- * If it is shorter than the specified length, it is padded with the
- * specified character at the front.
- * String#frontPadOrTruncateOn(int, char, StringBuilder)
- */
- public static void frontPadOrTruncateOn(char[] string, int length, char c, StringBuilder sb) {
- int stringLength = string.length;
- if (stringLength == length) {
- sb.append(string);
- } else if (stringLength > length) {
- sb.append(string, stringLength - length, length);
- } else {
- frontPadOn_(string, length, c, sb);
- }
- }
-
- /*
- * Front-pad the specified string without validating the parms.
- */
- private static String frontPad_(String string, int length, char c) {
- return new String(frontPad_(string.toCharArray(), length, c));
- }
-
- /*
- * Zero-pad the specified string without validating the parms.
- */
- private static char[] frontPad_(char[] string, int length, char c) {
- char[] result = new char[length];
- int stringLength = string.length;
- int padLength = length - stringLength;
- System.arraycopy(string, 0, result, padLength, stringLength);
- Arrays.fill(result, 0, padLength, c);
- return result;
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void frontPadOn_(String string, int length, char c, Writer writer) {
- fill_(string, length, c, writer);
- writeStringOn(string, writer);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void frontPadOn_(char[] string, int length, char c, Writer writer) {
- fill_(string, length, c, writer);
- writeStringOn(string, writer);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void frontPadOn_(String string, int length, char c, StringBuffer sb) {
- fill_(string, length, c, sb);
- sb.append(string);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void frontPadOn_(char[] string, int length, char c, StringBuffer sb) {
- fill_(string, length, c, sb);
- sb.append(string);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void frontPadOn_(String string, int length, char c, StringBuilder sb) {
- fill_(string, length, c, sb);
- sb.append(string);
- }
-
- /*
- * Pad the specified string without validating the parms.
- */
- private static void frontPadOn_(char[] string, int length, char c, StringBuilder sb) {
- fill_(string, length, c, sb);
- sb.append(string);
- }
-
-
- // ********** delimiting/quoting **********
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static String quote(String string) {
- return delimit(string, QUOTE);
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static void quoteOn(String string, Writer writer) {
- delimitOn(string, QUOTE, writer);
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static void quoteOn(String string, StringBuffer sb) {
- delimitOn(string, QUOTE, sb);
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static void quoteOn(String string, StringBuilder sb) {
- delimitOn(string, QUOTE, sb);
- }
-
- /**
- * Delimit each of the specified strings with double quotes.
- * Escape any occurrences of a double quote in a string with another
- * double quote.
- */
- public static Iterator<String> quote(Iterator<String> strings) {
- return delimit(strings, QUOTE);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static String delimit(String string, char delimiter) {
- return new String(delimit(string.toCharArray(), delimiter));
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static void delimitOn(String string, char delimiter, Writer writer) {
- delimitOn(string.toCharArray(), delimiter, writer);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static void delimitOn(String string, char delimiter, StringBuffer sb) {
- delimitOn(string.toCharArray(), delimiter, sb);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static void delimitOn(String string, char delimiter, StringBuilder sb) {
- delimitOn(string.toCharArray(), delimiter, sb);
- }
-
- /**
- * Delimit each of the specified strings with the specified delimiter; i.e. put a
- * copy of the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in a string with another delimiter.
- */
- public static Iterator<String> delimit(Iterator<String> strings, final char delimiter) {
- return new TransformationIterator<String, String>(strings) {
- @Override
- protected String transform(String string) {
- return StringTools.delimit(string, delimiter);
- }
- };
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static String delimit(String string, String delimiter) {
- if (delimiter.length() == 1) {
- return delimit(string, delimiter.charAt(0));
- }
- return new String(delimit(string.toCharArray(), delimiter.toCharArray()));
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static void delimitOn(String string, String delimiter, Writer writer) {
- if (delimiter.length() == 1) {
- delimitOn(string, delimiter.charAt(0), writer);
- } else {
- delimitOn(string.toCharArray(), delimiter.toCharArray(), writer);
- }
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static void delimitOn(String string, String delimiter, StringBuffer sb) {
- if (delimiter.length() == 1) {
- delimitOn(string, delimiter.charAt(0), sb);
- } else {
- delimitOn(string.toCharArray(), delimiter.toCharArray(), sb);
- }
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static void delimitOn(String string, String delimiter, StringBuilder sb) {
- if (delimiter.length() == 1) {
- delimitOn(string, delimiter.charAt(0), sb);
- } else {
- delimitOn(string.toCharArray(), delimiter.toCharArray(), sb);
- }
- }
-
- /**
- * Delimit each of the specified strings with the specified delimiter; i.e. put a
- * copy of the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in a string with
- * another delimiter.
- */
- public static Iterator<String> delimit(Iterator<String> strings, final String delimiter) {
- if (delimiter.length() == 1) {
- return delimit(strings, delimiter.charAt(0));
- }
- return new TransformationIterator<String, String>(strings) {
- @Override
- protected String transform(String string) {
- return StringTools.delimit(string, delimiter);
- }
- };
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static char[] quote(char[] string) {
- return delimit(string, QUOTE);
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static void quoteOn(char[] string, Writer writer) {
- delimitOn(string, QUOTE, writer);
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static void quoteOn(char[] string, StringBuffer sb) {
- delimitOn(string, QUOTE, sb);
- }
-
- /**
- * Delimit the specified string with double quotes.
- * Escape any occurrences of a double quote in the string with another
- * double quote.
- */
- public static void quoteOn(char[] string, StringBuilder sb) {
- delimitOn(string, QUOTE, sb);
- }
-
- /**
- * Delimit each of the specified strings with double quotes.
- * Escape any occurrences of a double quote in a string with another
- * double quote.
- */
- // cannot name method simply 'quote' because of type-erasure...
- public static Iterator<char[]> quoteCharArrays(Iterator<char[]> strings) {
- return delimitCharArrays(strings, QUOTE);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static char[] delimit(char[] string, char delimiter) {
- StringBuilder sb = new StringBuilder(string.length + 2);
- delimitOn(string, delimiter, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static void delimitOn(char[] string, char delimiter, Writer writer) {
- writeCharOn(delimiter, writer);
- writeStringOn(string, delimiter, writer);
- writeCharOn(delimiter, writer);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static void delimitOn(char[] string, char delimiter, StringBuffer sb) {
- sb.append(delimiter);
- for (char c : string) {
- if (c == delimiter) {
- sb.append(c);
- }
- sb.append(c);
- }
- sb.append(delimiter);
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in the string with another delimiter.
- */
- public static void delimitOn(char[] string, char delimiter, StringBuilder sb) {
- sb.append(delimiter);
- for (char c : string) {
- if (c == delimiter) {
- sb.append(c);
- }
- sb.append(c);
- }
- sb.append(delimiter);
- }
-
- /**
- * Delimit each of the specified strings with the specified delimiter; i.e. put a
- * copy of the delimiter at the front and back of the resulting string.
- * Escape any occurrences of the delimiter in a string with another delimiter.
- */
- // cannot name method simply 'delimit' because of type-erasure...
- public static Iterator<char[]> delimitCharArrays(Iterator<char[]> strings, final char delimiter) {
- return new TransformationIterator<char[], char[]>(strings) {
- @Override
- protected char[] transform(char[] string) {
- return StringTools.delimit(string, delimiter);
- }
- };
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static char[] delimit(char[] string, char[] delimiter) {
- int delimiterLength = delimiter.length;
- if (delimiterLength == 1) {
- return delimit(string, delimiter[0]);
- }
- int stringLength = string.length;
- char[] result = new char[stringLength+(2*delimiterLength)];
- System.arraycopy(delimiter, 0, result, 0, delimiterLength);
- System.arraycopy(string, 0, result, delimiterLength, stringLength);
- System.arraycopy(delimiter, 0, result, stringLength+delimiterLength, delimiterLength);
- return result;
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static void delimitOn(char[] string, char[] delimiter, Writer writer) {
- if (delimiter.length == 1) {
- delimitOn(string, delimiter[0], writer);
- } else {
- writeStringOn(delimiter, writer);
- writeStringOn(string, writer);
- writeStringOn(delimiter, writer);
- }
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static void delimitOn(char[] string, char[] delimiter, StringBuffer sb) {
- if (delimiter.length == 1) {
- delimitOn(string, delimiter[0], sb);
- } else {
- sb.append(delimiter);
- sb.append(string);
- sb.append(delimiter);
- }
- }
-
- /**
- * Delimit the specified string with the specified delimiter; i.e. put a copy of
- * the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in the string with
- * another delimiter.
- */
- public static void delimitOn(char[] string, char[] delimiter, StringBuilder sb) {
- if (delimiter.length == 1) {
- delimitOn(string, delimiter[0], sb);
- } else {
- sb.append(delimiter);
- sb.append(string);
- sb.append(delimiter);
- }
- }
-
- /**
- * Delimit each of the specified strings with the specified delimiter; i.e. put a
- * copy of the delimiter at the front and back of the resulting string.
- * Escape any occurrences of a single-character delimiter in a string with
- * another delimiter.
- */
- // cannot name method simply 'delimit' because of type-erasure...
- public static Iterator<char[]> delimitCharArrays(Iterator<char[]> strings, final char[] delimiter) {
- return new TransformationIterator<char[], char[]>(strings) {
- @Override
- protected char[] transform(char[] string) {
- return StringTools.delimit(string, delimiter);
- }
- };
- }
-
-
- // ********** delimiting queries **********
-
- /**
- * Return whether the specified string is quoted: "\"foo\"".
- */
- public static boolean stringIsQuoted(String string) {
- return stringIsDelimited(string, QUOTE);
- }
-
- /**
- * Return whether the specified string is parenthetical: "(foo)".
- */
- public static boolean stringIsParenthetical(String string) {
- return stringIsDelimited(string, OPEN_PARENTHESIS, CLOSE_PARENTHESIS);
- }
-
- /**
- * Return whether the specified string is bracketed: "[foo]".
- */
- public static boolean stringIsBracketed(String string) {
- return stringIsDelimited(string, OPEN_BRACKET, CLOSE_BRACKET);
- }
-
- /**
- * Return whether the specified string is braced: "{foo}".
- */
- public static boolean stringIsBraced(String string) {
- return stringIsDelimited(string, OPEN_BRACE, CLOSE_BRACE);
- }
-
- /**
- * Return whether the specified string is chevroned: "<foo>".
- */
- public static boolean stringIsChevroned(String string) {
- return stringIsDelimited(string, OPEN_CHEVRON, CLOSE_CHEVRON);
- }
-
- /**
- * Return whether the specified string is delimited by the specified
- * character.
- */
- public static boolean stringIsDelimited(String string, char c) {
- return stringIsDelimited(string, c, c);
- }
-
- /**
- * Return whether the specified string is delimited by the specified
- * characters.
- */
- public static boolean stringIsDelimited(String string, char start, char end) {
- int len = string.length();
- if (len < 2) {
- return false;
- }
- return stringIsDelimited(string.toCharArray(), start, end, len);
- }
-
- /**
- * Return whether the specified string is quoted: "\"foo\"".
- */
- public static boolean stringIsQuoted(char[] string) {
- return stringIsDelimited(string, QUOTE);
- }
-
- /**
- * Return whether the specified string is parenthetical: "(foo)".
- */
- public static boolean stringIsParenthetical(char[] string) {
- return stringIsDelimited(string, OPEN_PARENTHESIS, CLOSE_PARENTHESIS);
- }
-
- /**
- * Return whether the specified string is bracketed: "[foo]".
- */
- public static boolean stringIsBracketed(char[] string) {
- return stringIsDelimited(string, OPEN_BRACKET, CLOSE_BRACKET);
- }
-
- /**
- * Return whether the specified string is braced: "{foo}".
- */
- public static boolean stringIsBraced(char[] string) {
- return stringIsDelimited(string, OPEN_BRACE, CLOSE_BRACE);
- }
-
- /**
- * Return whether the specified string is chevroned: "<foo>".
- */
- public static boolean stringIsChevroned(char[] string) {
- return stringIsDelimited(string, OPEN_CHEVRON, CLOSE_CHEVRON);
- }
-
- /**
- * Return whether the specified string is delimited by the specified
- * character.
- */
- public static boolean stringIsDelimited(char[] string, char c) {
- return stringIsDelimited(string, c, c);
- }
-
- /**
- * Return whether the specified string is delimited by the specified
- * characters.
- */
- public static boolean stringIsDelimited(char[] string, char start, char end) {
- int len = string.length;
- if (len < 2) {
- return false;
- }
- return stringIsDelimited(string, start, end, len);
- }
-
- private static boolean stringIsDelimited(char[] s, char start, char end, int len) {
- return (s[0] == start) && (s[len - 1] == end);
- }
-
-
- // ********** undelimiting **********
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static String undelimit(String string) {
- int len = string.length() - 2;
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + string + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return EMPTY_STRING;
- }
- return new String(undelimit_(string.toCharArray(), len));
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static String undelimit(String string, int count) {
- int len = string.length() - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + string + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return EMPTY_STRING;
- }
- return new String(undelimit(string.toCharArray(), len, count));
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static char[] undelimit(char[] string) {
- int len = string.length - 2;
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return EMPTY_CHAR_ARRAY;
- }
- return undelimit_(string, len);
- }
-
- private static char[] undelimit_(char[] string, int length) {
- StringBuilder sb = new StringBuilder(length);
- undelimitOn_(string, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static char[] undelimit(char[] string, int count) {
- int len = string.length - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return EMPTY_CHAR_ARRAY;
- }
- return undelimit(string, len, count);
- }
-
- private static char[] undelimit(char[] string, int len, int count) {
- char[] result = new char[len];
- System.arraycopy(string, count, result, 0, len);
- return result;
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static void undelimitOn(String string, Writer writer) {
- undelimitOn(string.toCharArray(), writer);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static void undelimitOn(String string, int count, Writer writer) {
- int len = string.length() - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + string + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- writeStringOn(string, count, len, writer);
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static void undelimitOn(String string, StringBuffer sb) {
- undelimitOn(string.toCharArray(), sb);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static void undelimitOn(String string, int count, StringBuffer sb) {
- int len = string.length() - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + string + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- sb.append(string, count, count + len);
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static void undelimitOn(String string, StringBuilder sb) {
- undelimitOn(string.toCharArray(), sb);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static void undelimitOn(String string, int count, StringBuilder sb) {
- int len = string.length() - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + string + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- sb.append(string, count, count + len);
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static void undelimitOn(char[] string, Writer writer) {
- int len = string.length - 2;
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- undelimitOn_(string, writer);
- }
-
- /**
- * pre-condition: string is at least 3 characters long
- */
- private static void undelimitOn_(char[] string, Writer writer) {
- char delimiter = string[0]; // the first char is the delimiter
- char c = string[0];
- char next = string[1];
- int i = 1;
- int last = string.length - 1;
- do {
- c = next;
- writeCharOn(c, writer);
- i++;
- next = string[i];
- if (c == delimiter) {
- if ((next != delimiter) || (i == last)) {
- // an embedded delimiter must be followed by another delimiter
- return;
- }
- i++;
- next = string[i];
- }
- } while (i != last);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static void undelimitOn(char[] string, int count, Writer writer) {
- int len = string.length - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- writeStringOn(string, count, len, writer);
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static void undelimitOn(char[] string, StringBuffer sb) {
- int len = string.length - 2;
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- undelimitOn_(string, sb);
- }
-
- /**
- * pre-condition: string is at least 3 characters long
- */
- private static void undelimitOn_(char[] string, StringBuffer sb) {
- char delimiter = string[0]; // the first char is the delimiter
- char c = string[0];
- char next = string[1];
- int i = 1;
- int last = string.length - 1;
- do {
- c = next;
- sb.append(c);
- i++;
- next = string[i];
- if (c == delimiter) {
- if ((next != delimiter) || (i == last)) {
- // an embedded delimiter must be followed by another delimiter
- return;
- }
- i++;
- next = string[i];
- }
- } while (i != last);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static void undelimitOn(char[] string, int count, StringBuffer sb) {
- int len = string.length - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- sb.append(string, count, len);
- }
-
- /**
- * Remove the delimiters from the specified string, removing any escape
- * characters. Throw an IllegalArgumentException if the string is too short
- * to undelimit (i.e. length < 2).
- */
- public static void undelimitOn(char[] string, StringBuilder sb) {
- int len = string.length - 2;
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- undelimitOn_(string, sb);
- }
-
- /**
- * pre-condition: string is at least 3 characters long
- */
- private static void undelimitOn_(char[] string, StringBuilder sb) {
- char delimiter = string[0]; // the first char is the delimiter
- char c = string[0];
- char next = string[1];
- int i = 1;
- int last = string.length - 1;
- do {
- c = next;
- sb.append(c);
- i++;
- next = string[i];
- if (c == delimiter) {
- if ((next != delimiter) || (i == last)) {
- // an embedded delimiter must be followed by another delimiter
- return;
- }
- i++;
- next = string[i];
- }
- } while (i != last);
- }
-
- /**
- * Remove the first and last count characters from the specified string.
- * If the string is too short to be undelimited, throw an
- * IllegalArgumentException.
- * Use this method to undelimit strings that do not escape embedded
- * delimiters.
- */
- public static void undelimitOn(char[] string, int count, StringBuilder sb) {
- int len = string.length - (2 * count);
- if (len < 0) {
- throw new IllegalArgumentException("invalid string: \"" + new String(string) + '"'); //$NON-NLS-1$
- }
- if (len == 0) {
- return;
- }
- sb.append(string, count, len);
- }
-
-
- // ********** removing characters **********
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and return the result.
- * String#removeFirstOccurrence(char)
- */
- public static String removeFirstOccurrence(String string, char c) {
- int index = string.indexOf(c);
- if (index == -1) {
- // character not found
- return string;
- }
- if (index == 0) {
- // character found at the front of string
- return string.substring(1);
- }
- int last = string.length() - 1;
- if (index == last) {
- // character found at the end of string
- return string.substring(0, last);
- }
- // character found somewhere in the middle of the string
- return string.substring(0, index).concat(string.substring(index + 1));
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and print the result on the specified stream.
- * String#removeFirstOccurrenceOn(char, Writer)
- */
- public static void removeFirstOccurrenceOn(String string, char c, Writer writer) {
- int index = string.indexOf(c);
- if (index == -1) {
- writeStringOn(string, writer);
- } else {
- removeCharAtIndexOn(string.toCharArray(), index, writer);
- }
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and print the result on the specified stream.
- * String#removeFirstOccurrenceOn(char, StringBuffer)
- */
- public static void removeFirstOccurrenceOn(String string, char c, StringBuffer sb) {
- int index = string.indexOf(c);
- if (index == -1) {
- sb.append(string);
- } else {
- removeCharAtIndexOn(string.toCharArray(), index, sb);
- }
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and print the result on the specified stream.
- * String#removeFirstOccurrenceOn(char, StringBuilder)
- */
- public static void removeFirstOccurrenceOn(String string, char c, StringBuilder sb) {
- int index = string.indexOf(c);
- if (index == -1) {
- sb.append(string);
- } else {
- removeCharAtIndexOn(string.toCharArray(), index, sb);
- }
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and return the result.
- * String#removeFirstOccurrence(char)
- */
- public static char[] removeFirstOccurrence(char[] string, char c) {
- int index = CollectionTools.indexOf(string, c);
- if (index == -1) {
- // character not found
- return string;
- }
- int last = string.length - 1;
- char[] result = new char[last];
- if (index == 0) {
- // character found at the front of string
- System.arraycopy(string, 1, result, 0, last);
- } else if (index == last) {
- // character found at the end of string
- System.arraycopy(string, 0, result, 0, last);
- } else {
- // character found somewhere in the middle of the string
- System.arraycopy(string, 0, result, 0, index);
- System.arraycopy(string, index + 1, result, index, last - index);
- }
- return result;
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and print the result on the specified stream.
- * String#removeFirstOccurrenceOn(char, Writer)
- */
- public static void removeFirstOccurrenceOn(char[] string, char c, Writer writer) {
- int index = CollectionTools.indexOf(string, c);
- if (index == -1) {
- writeStringOn(string, writer);
- } else {
- removeCharAtIndexOn(string, index, writer);
- }
- }
-
- private static void removeCharAtIndexOn(char[] string, int index, Writer writer) {
- int last = string.length - 1;
- if (index == 0) {
- // character found at the front of string
- writeStringOn(string, 1, last, writer);
- } else if (index == last) {
- // character found at the end of string
- writeStringOn(string, 0, last, writer);
- } else {
- // character found somewhere in the middle of the string
- writeStringOn(string, 0, index, writer);
- writeStringOn(string, index + 1, last - index, writer);
- }
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and print the result on the specified stream.
- * String#removeFirstOccurrenceOn(char, StringBuffer)
- */
- public static void removeFirstOccurrenceOn(char[] string, char c, StringBuffer sb) {
- int index = CollectionTools.indexOf(string, c);
- if (index == -1) {
- sb.append(string);
- } else {
- removeCharAtIndexOn(string, index, sb);
- }
- }
-
- private static void removeCharAtIndexOn(char[] string, int index, StringBuffer sb) {
- int last = string.length - 1;
- if (index == 0) {
- // character found at the front of string
- sb.append(string, 1, last);
- } else if (index == last) {
- // character found at the end of string
- sb.append(string, 0, last);
- } else {
- // character found somewhere in the middle of the string
- sb.append(string, 0, index);
- sb.append(string, index + 1, last - index);
- }
- }
-
- /**
- * Remove the first occurrence of the specified character
- * from the specified string and print the result on the specified stream.
- * String#removeFirstOccurrenceOn(char, StringBuilder)
- */
- public static void removeFirstOccurrenceOn(char[] string, char c, StringBuilder sb) {
- int index = CollectionTools.indexOf(string, c);
- if (index == -1) {
- sb.append(string);
- } else {
- removeCharAtIndexOn(string, index, sb);
- }
- }
-
- private static void removeCharAtIndexOn(char[] string, int index, StringBuilder sb) {
- int last = string.length - 1;
- if (index == 0) {
- // character found at the front of string
- sb.append(string, 1, last);
- } else if (index == last) {
- // character found at the end of string
- sb.append(string, 0, last);
- } else {
- // character found somewhere in the middle of the string
- sb.append(string, 0, index);
- sb.append(string, index + 1, last - index);
- }
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and return the result.
- * String#removeAllOccurrences(char)
- */
- public static String removeAllOccurrences(String string, char c) {
- int first = string.indexOf(c);
- return (first == -1) ? string : new String(removeAllOccurrences_(string.toCharArray(), c, first));
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and write the result to the specified stream.
- * String#removeAllOccurrencesOn(char, Writer)
- */
- public static void removeAllOccurrencesOn(String string, char c, Writer writer) {
- int first = string.indexOf(c);
- if (first == -1) {
- writeStringOn(string, writer);
- } else {
- removeAllOccurrencesOn_(string.toCharArray(), c, first, writer);
- }
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and write the result to the specified stream.
- * String#removeAllOccurrencesOn(char, StringBuffer)
- */
- public static void removeAllOccurrencesOn(String string, char c, StringBuffer sb) {
- int first = string.indexOf(c);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllOccurrencesOn_(string.toCharArray(), c, first, sb);
- }
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and write the result to the specified stream.
- * String#removeAllOccurrencesOn(char, StringBuilder)
- */
- public static void removeAllOccurrencesOn(String string, char c, StringBuilder sb) {
- int first = string.indexOf(c);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllOccurrencesOn_(string.toCharArray(), c, first, sb);
- }
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and return the result.
- * String#removeAllOccurrences(char)
- */
- public static char[] removeAllOccurrences(char[] string, char c) {
- int first = CollectionTools.indexOf(string, c);
- return (first == -1) ? string : removeAllOccurrences_(string, c, first);
- }
-
- /*
- * The index of the first matching character is passed in.
- */
- private static char[] removeAllOccurrences_(char[] string, char c, int first) {
- StringBuilder sb = new StringBuilder(string.length);
- removeAllOccurrencesOn_(string, c, first, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and write the result to the
- * specified writer.
- * String#removeAllOccurrencesOn(char, Writer)
- */
- public static void removeAllOccurrencesOn(char[] string, char c, Writer writer) {
- int first = CollectionTools.indexOf(string, c);
- if (first == -1) {
- writeStringOn(string, writer);
- } else {
- removeAllOccurrencesOn_(string, c, first, writer);
- }
- }
-
- /*
- * The index of the first matching character is passed in.
- */
- private static void removeAllOccurrencesOn_(char[] string, char c, int first, Writer writer) {
- writeStringOn(string, 0, first, writer);
- int len = string.length;
- for (int i = first; i < len; i++) {
- char d = string[i];
- if (d != c) {
- writeCharOn(d, writer);
- }
- }
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and append the result to the
- * specified string buffer.
- * String#removeAllOccurrencesOn(char, StringBuffer)
- */
- public static void removeAllOccurrencesOn(char[] string, char c, StringBuffer sb) {
- int first = CollectionTools.indexOf(string, c);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllOccurrencesOn_(string, c, first, sb);
- }
- }
-
- /*
- * The index of the first matching character is passed in.
- */
- private static void removeAllOccurrencesOn_(char[] string, char c, int first, StringBuffer sb) {
- sb.append(string, 0, first);
- int len = string.length;
- for (int i = first; i < len; i++) {
- char d = string[i];
- if (d != c) {
- sb.append(d);
- }
- }
- }
-
- /**
- * Remove all occurrences of the specified character
- * from the specified string and append the result to the
- * specified string builder.
- * String#removeAllOccurrencesOn(char, StringBuilder)
- */
- public static void removeAllOccurrencesOn(char[] string, char c, StringBuilder sb) {
- int first = CollectionTools.indexOf(string, c);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllOccurrencesOn_(string, c, first, sb);
- }
- }
-
- /*
- * The index of the first matching character is passed in.
- */
- private static void removeAllOccurrencesOn_(char[] string, char c, int first, StringBuilder sb) {
- sb.append(string, 0, first);
- int len = string.length;
- for (int i = first; i < len; i++) {
- char d = string[i];
- if (d != c) {
- sb.append(d);
- }
- }
- }
-
- /**
- * Remove all the spaces from the specified string and return the result.
- * String#removeAllSpaces()
- */
- public static String removeAllSpaces(String string) {
- return removeAllOccurrences(string, ' ');
- }
-
- /**
- * Remove all the spaces
- * from the specified string and write the result to the specified writer.
- * String#removeAllSpacesOn(Writer)
- */
- public static void removeAllSpacesOn(String string, Writer writer) {
- removeAllOccurrencesOn(string, ' ', writer);
- }
-
- /**
- * Remove all the spaces
- * from the specified string and write the result to the specified
- * string buffer.
- * String#removeAllSpacesOn(StringBuffer)
- */
- public static void removeAllSpacesOn(String string, StringBuffer sb) {
- removeAllOccurrencesOn(string, ' ', sb);
- }
-
- /**
- * Remove all the spaces
- * from the specified string and write the result to the specified
- * string builder.
- * String#removeAllSpacesOn(StringBuilder)
- */
- public static void removeAllSpacesOn(String string, StringBuilder sb) {
- removeAllOccurrencesOn(string, ' ', sb);
- }
-
- /**
- * Remove all the spaces from the specified string and return the result.
- * String#removeAllSpaces()
- */
- public static char[] removeAllSpaces(char[] string) {
- return removeAllOccurrences(string, ' ');
- }
-
- /**
- * Remove all the spaces
- * from the specified string and write the result to the
- * specified writer.
- * String#removeAllSpacesOn(Writer)
- */
- public static void removeAllSpacesOn(char[] string, Writer writer) {
- removeAllOccurrencesOn(string, ' ', writer);
- }
-
- /**
- * Remove all the spaces
- * from the specified string and append the result to the
- * specified string buffer.
- * String#removeAllSpacesOn(StringBuffer)
- */
- public static void removeAllSpacesOn(char[] string, StringBuffer sb) {
- removeAllOccurrencesOn(string, ' ', sb);
- }
-
- /**
- * Remove all the spaces
- * from the specified string and append the result to the
- * specified string builder.
- * String#removeAllSpacesOn(StringBuilder)
- */
- public static void removeAllSpacesOn(char[] string, StringBuilder sb) {
- removeAllOccurrencesOn(string, ' ', sb);
- }
-
- /**
- * Remove all the whitespace from the specified string and return the result.
- * String#removeAllWhitespace()
- */
- public static String removeAllWhitespace(String string) {
- char[] string2 = string.toCharArray();
- int first = indexOfWhitespace_(string2);
- return (first == -1) ? string : new String(removeAllWhitespace_(string2, first));
- }
-
- /**
- * Remove all the whitespace
- * from the specified string and append the result to the
- * specified writer.
- * String#removeAllWhitespaceOn(Writer)
- */
- public static void removeAllWhitespaceOn(String string, Writer writer) {
- char[] string2 = string.toCharArray();
- int first = indexOfWhitespace_(string2);
- if (first == -1) {
- writeStringOn(string, writer);
- } else {
- removeAllWhitespaceOn_(string2, first, writer);
- }
- }
-
- /**
- * Remove all the whitespace
- * from the specified string and append the result to the
- * specified string buffer.
- * String#removeAllWhitespaceOn(StringBuffer)
- */
- public static void removeAllWhitespaceOn(String string, StringBuffer sb) {
- char[] string2 = string.toCharArray();
- int first = indexOfWhitespace_(string2);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllWhitespaceOn_(string2, first, sb);
- }
- }
-
- /**
- * Remove all the whitespace
- * from the specified string and append the result to the
- * specified string builder.
- * String#removeAllWhitespaceOn(StringBuilder)
- */
- public static void removeAllWhitespaceOn(String string, StringBuilder sb) {
- char[] string2 = string.toCharArray();
- int first = indexOfWhitespace_(string2);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllWhitespaceOn_(string2, first, sb);
- }
- }
-
- /**
- * Remove all the whitespace from the specified string and return the result.
- * String#removeAllWhitespace()
- */
- public static char[] removeAllWhitespace(char[] string) {
- int first = indexOfWhitespace_(string);
- return (first == -1) ? string : removeAllWhitespace_(string, first);
- }
-
- private static int indexOfWhitespace_(char[] string) {
- int len = string.length;
- for (int i = 0; i < len; i++) {
- if (Character.isWhitespace(string[i])) {
- return i;
- }
- }
- return -1;
- }
-
- /*
- * The index of the first non-whitespace character is passed in.
- */
- private static char[] removeAllWhitespace_(char[] string, int first) {
- StringBuilder sb = new StringBuilder(string.length);
- removeAllWhitespaceOn_(string, first, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Remove all the whitespace
- * from the specified string and append the result to the
- * specified writer.
- * String#removeAllWhitespaceOn(Writer)
- */
- public static void removeAllWhitespaceOn(char[] string, Writer writer) {
- int first = indexOfWhitespace_(string);
- if (first == -1) {
- writeStringOn(string, writer);
- } else {
- removeAllWhitespaceOn_(string, first, writer);
- }
- }
-
- /*
- * The index of the first non-whitespace character is passed in.
- */
- private static void removeAllWhitespaceOn_(char[] string, int first, Writer writer) {
- writeStringOn(string, 0, first, writer);
- int len = string.length;
- for (int i = first; i < len; i++) {
- char c = string[i];
- if ( ! Character.isWhitespace(c)) {
- writeCharOn(c, writer);
- }
- }
- }
-
- /**
- * Remove all the whitespace
- * from the specified string and append the result to the
- * specified string buffer.
- * String#removeAllWhitespaceOn(StringBuffer)
- */
- public static void removeAllWhitespaceOn(char[] string, StringBuffer sb) {
- int first = indexOfWhitespace_(string);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllWhitespaceOn_(string, first, sb);
- }
- }
-
- /*
- * The index of the first non-whitespace character is passed in.
- */
- private static void removeAllWhitespaceOn_(char[] string, int first, StringBuffer sb) {
- sb.append(string, 0, first);
- int len = string.length;
- for (int i = first; i < len; i++) {
- char c = string[i];
- if ( ! Character.isWhitespace(c)) {
- sb.append(c);
- }
- }
- }
-
- /**
- * Remove all the whitespace
- * from the specified string and append the result to the
- * specified string builder.
- * String#removeAllWhitespaceOn(StringBuilder)
- */
- public static void removeAllWhitespaceOn(char[] string, StringBuilder sb) {
- int first = indexOfWhitespace_(string);
- if (first == -1) {
- sb.append(string);
- } else {
- removeAllWhitespaceOn_(string, first, sb);
- }
- }
-
- /*
- * The index of the first non-whitespace character is passed in.
- */
- private static void removeAllWhitespaceOn_(char[] string, int first, StringBuilder sb) {
- sb.append(string, 0, first);
- int len = string.length;
- for (int i = first; i < len; i++) {
- char c = string[i];
- if ( ! Character.isWhitespace(c)) {
- sb.append(c);
- }
- }
- }
-
-
- // ********** common prefix **********
-
- /**
- * Return the length of the common prefix shared by the specified strings.
- * String#commonPrefixLength(String)
- */
- public static int commonPrefixLength(String s1, String s2) {
- return commonPrefixLength(s1.toCharArray(), s2.toCharArray());
- }
-
- /**
- * Return the length of the common prefix shared by the specified strings.
- */
- public static int commonPrefixLength(char[] s1, char[] s2) {
- return commonPrefixLength_(s1, s2, Math.min(s1.length, s2.length));
- }
-
- /**
- * Return the length of the common prefix shared by the specified strings;
- * but limit the length to the specified maximum.
- * String#commonPrefixLength(String, int)
- */
- public static int commonPrefixLength(String s1, String s2, int max) {
- return commonPrefixLength(s1.toCharArray(), s2.toCharArray(), max);
- }
-
- /**
- * Return the length of the common prefix shared by the specified strings;
- * but limit the length to the specified maximum.
- */
- public static int commonPrefixLength(char[] s1, char[] s2, int max) {
- return commonPrefixLength_(s1, s2, Math.min(max, Math.min(s1.length, s2.length)));
- }
-
- /*
- * Return the length of the common prefix shared by the specified strings;
- * but limit the length to the specified maximum. Assume the specified
- * maximum is less than the lengths of the specified strings.
- */
- private static int commonPrefixLength_(char[] s1, char[] s2, int max) {
- for (int i = 0; i < max; i++) {
- if (s1[i] != s2[i]) {
- return i;
- }
- }
- return max; // all the characters up to 'max' are the same
- }
-
-
- // ********** capitalization **********
-
- /*
- * no zero-length check or lower case check
- */
- private static char[] capitalize_(char[] string) {
- string[0] = Character.toUpperCase(string[0]);
- return string;
- }
-
- /**
- * Modify and return the specified string with
- * its first letter capitalized.
- */
- public static char[] capitalize(char[] string) {
- if ((string.length == 0) || Character.isUpperCase(string[0])) {
- return string;
- }
- return capitalize_(string);
- }
-
- /**
- * Return the specified string with its first letter capitalized.
- * String#capitalize()
- */
- public static String capitalize(String string) {
- if ((string.length() == 0) || Character.isUpperCase(string.charAt(0))) {
- return string;
- }
- return new String(capitalize_(string.toCharArray()));
- }
-
- /**
- * Modify each of the specified strings, capitalizing the first letter of
- * each.
- */
- public static Iterator<String> capitalize(Iterator<String> strings) {
- return new TransformationIterator<String, String>(strings) {
- @Override
- protected String transform(String string) {
- return StringTools.capitalize(string);
- }
- };
- }
-
- /**
- * Modify each of the specified strings, capitalizing the first letter of
- * each.
- */
- // cannot name method simply 'capitalize' because of type-erasure...
- public static Iterator<char[]> capitalizeCharArrays(Iterator<char[]> strings) {
- return new TransformationIterator<char[], char[]>(strings) {
- @Override
- protected char[] transform(char[] string) {
- return StringTools.capitalize(string);
- }
- };
- }
-
- /*
- * no zero-length check or upper case check
- */
- private static void capitalizeOn_(char[] string, StringBuffer sb) {
- sb.append(Character.toUpperCase(string[0]));
- sb.append(string, 1, string.length - 1);
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter capitalized.
- */
- public static void capitalizeOn(char[] string, StringBuffer sb) {
- if (string.length == 0) {
- return;
- }
- if (Character.isUpperCase(string[0])) {
- sb.append(string);
- } else {
- capitalizeOn_(string, sb);
- }
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter capitalized.
- * String#capitalizeOn(StringBuffer)
- */
- public static void capitalizeOn(String string, StringBuffer sb) {
- if (string.length() == 0) {
- return;
- }
- if (Character.isUpperCase(string.charAt(0))) {
- sb.append(string);
- } else {
- capitalizeOn_(string.toCharArray(), sb);
- }
- }
-
- /*
- * no zero-length check or upper case check
- */
- private static void capitalizeOn_(char[] string, StringBuilder sb) {
- sb.append(Character.toUpperCase(string[0]));
- sb.append(string, 1, string.length - 1);
- }
-
- /**
- * Append the specified string to the specified string builder
- * with its first letter capitalized.
- */
- public static void capitalizeOn(char[] string, StringBuilder sb) {
- if (string.length == 0) {
- return;
- }
- if (Character.isUpperCase(string[0])) {
- sb.append(string);
- } else {
- capitalizeOn_(string, sb);
- }
- }
-
- /**
- * Append the specified string to the specified string builder
- * with its first letter capitalized.
- * String#capitalizeOn(StringBuffer)
- */
- public static void capitalizeOn(String string, StringBuilder sb) {
- if (string.length() == 0) {
- return;
- }
- if (Character.isUpperCase(string.charAt(0))) {
- sb.append(string);
- } else {
- capitalizeOn_(string.toCharArray(), sb);
- }
- }
-
- /*
- * no zero-length check or upper case check
- */
- private static void capitalizeOn_(char[] string, Writer writer) {
- writeCharOn(Character.toUpperCase(string[0]), writer);
- writeStringOn(string, 1, string.length - 1, writer);
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter capitalized.
- */
- public static void capitalizeOn(char[] string, Writer writer) {
- if (string.length == 0) {
- return;
- }
- if (Character.isUpperCase(string[0])) {
- writeStringOn(string, writer);
- } else {
- capitalizeOn_(string, writer);
- }
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter capitalized.
- * String#capitalizeOn(Writer)
- */
- public static void capitalizeOn(String string, Writer writer) {
- if (string.length() == 0) {
- return;
- }
- if (Character.isUpperCase(string.charAt(0))) {
- writeStringOn(string, writer);
- } else {
- capitalizeOn_(string.toCharArray(), writer);
- }
- }
-
- /*
- * no zero-length check or lower case check
- */
- private static char[] uncapitalize_(char[] string) {
- string[0] = Character.toLowerCase(string[0]);
- return string;
- }
-
- private static boolean stringNeedNotBeUncapitalized_(char[] string) {
- if (string.length == 0) {
- return true;
- }
- if (Character.isLowerCase(string[0])) {
- return true;
- }
- // if both the first and second characters are capitalized,
- // return the string unchanged
- if ((string.length > 1)
- && Character.isUpperCase(string[1])
- && Character.isUpperCase(string[0])){
- return true;
- }
- return false;
- }
-
- /**
- * Modify and return the specified string with its
- * first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- */
- public static char[] uncapitalize(char[] string) {
- if (stringNeedNotBeUncapitalized_(string)) {
- return string;
- }
- return uncapitalize_(string);
- }
-
- private static boolean stringNeedNotBeUncapitalized_(String string) {
- if (string.length() == 0) {
- return true;
- }
- if (Character.isLowerCase(string.charAt(0))) {
- return true;
- }
- // if both the first and second characters are capitalized,
- // return the string unchanged
- if ((string.length() > 1)
- && Character.isUpperCase(string.charAt(1))
- && Character.isUpperCase(string.charAt(0))){
- return true;
- }
- return false;
- }
-
- /**
- * Return the specified string with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- * String#uncapitalize()
- */
- public static String uncapitalize(String string) {
- if (stringNeedNotBeUncapitalized_(string)) {
- return string;
- }
- return new String(uncapitalize_(string.toCharArray()));
- }
-
- /*
- * no zero-length check or lower case check
- */
- private static void uncapitalizeOn_(char[] string, StringBuffer sb) {
- sb.append(Character.toLowerCase(string[0]));
- sb.append(string, 1, string.length - 1);
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- */
- public static void uncapitalizeOn(char[] string, StringBuffer sb) {
- if (stringNeedNotBeUncapitalized_(string)) {
- sb.append(string);
- } else {
- uncapitalizeOn_(string, sb);
- }
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- * String#uncapitalizeOn(StringBuffer)
- */
- public static void uncapitalizeOn(String string, StringBuffer sb) {
- if (stringNeedNotBeUncapitalized_(string)) {
- sb.append(string);
- } else {
- uncapitalizeOn_(string.toCharArray(), sb);
- }
- }
-
- /*
- * no zero-length check or lower case check
- */
- private static void uncapitalizeOn_(char[] string, StringBuilder sb) {
- sb.append(Character.toLowerCase(string[0]));
- sb.append(string, 1, string.length - 1);
- }
-
- /**
- * Append the specified string to the specified string builder
- * with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- */
- public static void uncapitalizeOn(char[] string, StringBuilder sb) {
- if (stringNeedNotBeUncapitalized_(string)) {
- sb.append(string);
- } else {
- uncapitalizeOn_(string, sb);
- }
- }
-
- /**
- * Append the specified string to the specified string builder
- * with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- * String#uncapitalizeOn(StringBuffer)
- */
- public static void uncapitalizeOn(String string, StringBuilder sb) {
- if (stringNeedNotBeUncapitalized_(string)) {
- sb.append(string);
- } else {
- uncapitalizeOn_(string.toCharArray(), sb);
- }
- }
-
- /*
- * no zero-length check or upper case check
- */
- private static void uncapitalizeOn_(char[] string, Writer writer) {
- writeCharOn(Character.toLowerCase(string[0]), writer);
- writeStringOn(string, 1, string.length - 1, writer);
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- */
- public static void uncapitalizeOn(char[] string, Writer writer) {
- if (stringNeedNotBeUncapitalized_(string)) {
- writeStringOn(string, writer);
- } else {
- uncapitalizeOn_(string, writer);
- }
- }
-
- /**
- * Append the specified string to the specified string buffer
- * with its first letter converted to lower case.
- * (Unless both the first and second letters are upper case,
- * in which case the string is returned unchanged.)
- * String#uncapitalizeOn(Writer)
- */
- public static void uncapitalizeOn(String string, Writer writer) {
- if (stringNeedNotBeUncapitalized_(string)) {
- writeStringOn(string, writer);
- } else {
- uncapitalizeOn_(string.toCharArray(), writer);
- }
- }
-
-
- // ********** #toString() helper methods **********
-
- /**
- * Build a "standard" #toString() result for the specified object
- * and additional information:
- * ClassName[00F3EE42] (add'l info)
- */
- public static String buildToStringFor(Object o, Object additionalInfo) {
- StringBuilder sb = new StringBuilder();
- buildSimpleToStringOn(o, sb);
- sb.append(" ("); //$NON-NLS-1$
- sb.append(additionalInfo);
- sb.append(')');
- return sb.toString();
- }
-
- /**
- * Build a "standard" simple #toString() result for the specified object:
- * ClassName[00F3EE42]
- */
- public static String buildToStringFor(Object o) {
- StringBuilder sb = new StringBuilder();
- buildSimpleToStringOn(o, sb);
- return sb.toString();
- }
-
- /**
- * Append a "standard" simple #toString() for the specified object to
- * the specified string buffer:
- * ClassName[00F3EE42]
- */
- public static void buildSimpleToStringOn(Object o, StringBuffer sb) {
- sb.append(ClassTools.toStringClassNameForObject(o));
- sb.append('[');
- // use System#identityHashCode(Object), since Object#hashCode() may be overridden
- sb.append(zeroPad(Integer.toHexString(System.identityHashCode(o)).toUpperCase(), 8));
- sb.append(']');
- }
-
- /**
- * Append a "standard" simple #toString() for the specified object to
- * the specified string builder:
- * ClassName[00F3EE42]
- */
- public static void buildSimpleToStringOn(Object o, StringBuilder sb) {
- sb.append(ClassTools.toStringClassNameForObject(o));
- sb.append('[');
- // use System#identityHashCode(Object), since Object#hashCode() may be overridden
- sb.append(zeroPad(Integer.toHexString(System.identityHashCode(o)).toUpperCase(), 8));
- sb.append(']');
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether the specified string is null, empty, or contains
- * only whitespace characters.
- */
- public static boolean stringIsEmpty(String string) {
- if (string == null) {
- return true;
- }
- int len = string.length();
- if (len == 0) {
- return true;
- }
- return stringIsEmpty_(string.toCharArray(), len);
- }
-
- /**
- * Return whether the specified string is null, empty, or contains
- * only whitespace characters.
- */
- public static boolean stringIsEmpty(char[] string) {
- if (string == null) {
- return true;
- }
- int len = string.length;
- if (len == 0) {
- return true;
- }
- return stringIsEmpty_(string, len);
- }
-
- private static boolean stringIsEmpty_(char[] s, int len) {
- for (int i = len; i-- > 0; ) {
- if ( ! Character.isWhitespace(s[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified string is non-null, non-empty, and does
- * not contain only whitespace characters.
- */
- public static boolean stringIsNotEmpty(String string) {
- return ! stringIsEmpty(string);
- }
-
- /**
- * Return whether the specified string is non-null, non-empty, and does
- * not contain only whitespace characters.
- */
- public static boolean stringIsNotEmpty(char[] string) {
- return ! stringIsEmpty(string);
- }
-
- /**
- * Return whether the specified strings are equal, ignoring case.
- * Check for nulls.
- */
- public static boolean stringsAreEqualIgnoreCase(String s1, String s2) {
- if ((s1 == null) && (s2 == null)) {
- return true; // both are null
- }
- if ((s1 == null) || (s2 == null)) {
- return false; // one is null but the other is not
- }
- return s1.equalsIgnoreCase(s2);
- }
-
- /**
- * Return whether the specified strings are equal, ignoring case.
- * Check for nulls.
- */
- public static boolean stringsAreEqualIgnoreCase(char[] s1, char[] s2) {
- if ((s1 == null) && (s2 == null)) {
- return true; // both are null
- }
- if ((s1 == null) || (s2 == null)) {
- return false; // one is null but the other is not
- }
- int len = s1.length;
- if (len != s2.length) {
- return false;
- }
- for (int i = len; i-- > 0; ) {
- if ( ! charactersAreEqualIgnoreCase(s1[i], s2[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified string starts with the specified prefix,
- * ignoring case.
- */
- public static boolean stringStartsWithIgnoreCase(char[] string, char[] prefix) {
- int prefixLength = prefix.length;
- if (string.length < prefixLength) {
- return false;
- }
- for (int i = prefixLength; i-- > 0; ) {
- if ( ! charactersAreEqualIgnoreCase(string[i], prefix[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Return whether the specified string starts with the specified prefix,
- * ignoring case.
- */
- public static boolean stringStartsWithIgnoreCase(String string, String prefix) {
- return string.regionMatches(true, 0, prefix, 0, prefix.length());
- }
-
- /**
- * Return whether the specified characters are are equal, ignoring case.
- * @see java.lang.String#regionMatches(boolean, int, String, int, int)
- */
- public static boolean charactersAreEqualIgnoreCase(char c1, char c2) {
- // something about the Georgian alphabet requires us to check lower case also
- return (c1 == c2)
- || (Character.toUpperCase(c1) == Character.toUpperCase(c2))
- || (Character.toLowerCase(c1) == Character.toLowerCase(c2));
- }
-
- /**
- * Return whether the specified string is uppercase.
- */
- public static boolean stringIsUppercase(String string) {
- return (string.length() == 0) ? false : stringIsUppercase_(string);
- }
-
- /**
- * Return whether the specified string is uppercase.
- */
- public static boolean stringIsUppercase(char[] string) {
- return (string.length == 0) ? false : stringIsUppercase_(new String(string));
- }
-
- private static boolean stringIsUppercase_(String string) {
- return string.equals(string.toUpperCase());
- }
-
- /**
- * Return whether the specified string is lowercase.
- */
- public static boolean stringIsLowercase(String string) {
- return (string.length() == 0) ? false : stringIsLowercase_(string);
- }
-
- /**
- * Return whether the specified string is lowercase.
- */
- public static boolean stringIsLowercase(char[] string) {
- return (string.length == 0) ? false : stringIsLowercase_(new String(string));
- }
-
- private static boolean stringIsLowercase_(String string) {
- return string.equals(string.toLowerCase());
- }
-
-
- // ********** convert camel case to all caps **********
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static String convertCamelCaseToAllCaps(String camelCaseString) {
- int len = camelCaseString.length();
- if (len == 0) {
- return camelCaseString;
- }
- return new String(convertCamelCaseToAllCaps_(camelCaseString.toCharArray(), len));
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static char[] convertCamelCaseToAllCaps(char[] camelCaseString) {
- int len = camelCaseString.length;
- if (len == 0) {
- return camelCaseString;
- }
- return convertCamelCaseToAllCaps_(camelCaseString, len);
- }
-
- private static char[] convertCamelCaseToAllCaps_(char[] camelCaseString, int len) {
- StringBuilder sb = new StringBuilder(len * 2);
- convertCamelCaseToAllCapsOn_(camelCaseString, len, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static void convertCamelCaseToAllCapsOn(String camelCaseString, StringBuffer sb) {
- int len = camelCaseString.length();
- if (len != 0) {
- convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), len, sb);
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, StringBuffer sb) {
- int len = camelCaseString.length;
- if (len != 0) {
- convertCamelCaseToAllCapsOn_(camelCaseString, len, sb);
- }
- }
-
- private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int len, StringBuffer sb) {
- char prev = 0; // assume 0 is not a valid char
- char c = 0;
- char next = camelCaseString[0];
- for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len!
- c = next;
- next = ((i == len) ? 0 : camelCaseString[i]);
- if (camelCaseWordBreak_(prev, c, next)) {
- sb.append('_');
- }
- sb.append(Character.toUpperCase(c));
- prev = c;
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static void convertCamelCaseToAllCapsOn(String camelCaseString, StringBuilder sb) {
- int len = camelCaseString.length();
- if (len != 0) {
- convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), len, sb);
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, StringBuilder sb) {
- int len = camelCaseString.length;
- if (len != 0) {
- convertCamelCaseToAllCapsOn_(camelCaseString, len, sb);
- }
- }
-
- private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int len, StringBuilder sb) {
- char prev = 0; // assume 0 is not a valid char
- char c = 0;
- char next = camelCaseString[0];
- for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len!
- c = next;
- next = ((i == len) ? 0 : camelCaseString[i]);
- if (camelCaseWordBreak_(prev, c, next)) {
- sb.append('_');
- }
- sb.append(Character.toUpperCase(c));
- prev = c;
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static void convertCamelCaseToAllCapsOn(String camelCaseString, Writer writer) {
- int len = camelCaseString.length();
- if (len != 0) {
- convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), len, writer);
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- */
- public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, Writer writer) {
- int len = camelCaseString.length;
- if (len != 0) {
- convertCamelCaseToAllCapsOn_(camelCaseString, len, writer);
- }
- }
-
- private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int len, Writer writer) {
- char prev = 0; // assume 0 is not a valid char
- char c = 0;
- char next = camelCaseString[0];
- for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len!
- c = next;
- next = ((i == len) ? 0 : camelCaseString[i]);
- if (camelCaseWordBreak_(prev, c, next)) {
- writeCharOn('_', writer);
- }
- writeCharOn(Character.toUpperCase(c), writer);
- prev = c;
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static String convertCamelCaseToAllCaps(String camelCaseString, int maxLength) {
- int len = camelCaseString.length();
- if ((len == 0) || (maxLength == 0)) {
- return camelCaseString;
- }
- return new String(convertCamelCaseToAllCaps_(camelCaseString.toCharArray(), maxLength, len));
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static char[] convertCamelCaseToAllCaps(char[] camelCaseString, int maxLength) {
- int len = camelCaseString.length;
- if ((len == 0) || (maxLength == 0)) {
- return camelCaseString;
- }
- return convertCamelCaseToAllCaps_(camelCaseString, maxLength, len);
- }
-
- private static char[] convertCamelCaseToAllCaps_(char[] camelCaseString, int maxLength, int len) {
- StringBuilder sb = new StringBuilder(maxLength);
- convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, StringBuffer sb) {
- int len = camelCaseString.length();
- if ((len != 0) && (maxLength != 0)) {
- convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), maxLength, len, sb);
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, StringBuffer sb) {
- int len = camelCaseString.length;
- if ((len != 0) && (maxLength != 0)) {
- convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, sb);
- }
- }
-
- private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int maxLength, int len, StringBuffer sb) {
- char prev = 0; // assume 0 is not a valid char
- char c = 0;
- char next = camelCaseString[0];
- for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len!
- c = next;
- next = ((i == len) ? 0 : camelCaseString[i]);
- if (camelCaseWordBreak_(prev, c, next)) {
- sb.append('_');
- if (sb.length() == maxLength) {
- return;
- }
- }
- sb.append(Character.toUpperCase(c));
- if (sb.length() == maxLength) {
- return;
- }
- prev = c;
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, StringBuilder sb) {
- int len = camelCaseString.length();
- if ((len != 0) && (maxLength != 0)) {
- convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), maxLength, len, sb);
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, StringBuilder sb) {
- int len = camelCaseString.length;
- if ((len != 0) && (maxLength != 0)) {
- convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, sb);
- }
- }
-
- private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int maxLength, int len, StringBuilder sb) {
- char prev = 0; // assume 0 is not a valid char
- char c = 0;
- char next = camelCaseString[0];
- for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len!
- c = next;
- next = ((i == len) ? 0 : camelCaseString[i]);
- if (camelCaseWordBreak_(prev, c, next)) {
- sb.append('_');
- if (sb.length() == maxLength) {
- return;
- }
- }
- sb.append(Character.toUpperCase(c));
- if (sb.length() == maxLength) {
- return;
- }
- prev = c;
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static void convertCamelCaseToAllCapsOn(String camelCaseString, int maxLength, Writer writer) {
- int len = camelCaseString.length();
- if ((len != 0) && (maxLength != 0)) {
- convertCamelCaseToAllCapsOn_(camelCaseString.toCharArray(), maxLength, len, writer);
- }
- }
-
- /**
- * Convert the specified "camel case" string to an "all caps" string:
- * "largeProject" -> "LARGE_PROJECT"
- * Limit the resulting string to the specified maximum length.
- */
- public static void convertCamelCaseToAllCapsOn(char[] camelCaseString, int maxLength, Writer writer) {
- int len = camelCaseString.length;
- if ((len != 0) && (maxLength != 0)) {
- convertCamelCaseToAllCapsOn_(camelCaseString, maxLength, len, writer);
- }
- }
-
- private static void convertCamelCaseToAllCapsOn_(char[] camelCaseString, int maxLength, int len, Writer writer) {
- char prev = 0; // assume 0 is not a valid char
- char c = 0;
- char next = camelCaseString[0];
- int writerLength = 0;
- for (int i = 1; i <= len; i++) { // NB: start at 1 and end at len!
- c = next;
- next = ((i == len) ? 0 : camelCaseString[i]);
- if (camelCaseWordBreak_(prev, c, next)) {
- writeCharOn('_', writer);
- if (++writerLength == maxLength) {
- return;
- }
- }
- writeCharOn(Character.toUpperCase(c), writer);
- if (++writerLength == maxLength) {
- return;
- }
- prev = c;
- }
- }
-
- /*
- * Return whether the specified series of characters occur at
- * a "camel case" work break:
- * "*aa" -> false
- * "*AA" -> false
- * "*Aa" -> false
- * "AaA" -> false
- * "AAA" -> false
- * "aa*" -> false
- * "AaA" -> false
- * "aAa" -> true
- * "AA*" -> false
- * "AAa" -> true
- * where '*' == any char
- */
- private static boolean camelCaseWordBreak_(char prev, char c, char next) {
- if (prev == 0) { // start of string
- return false;
- }
- if (Character.isLowerCase(c)) {
- return false;
- }
- if (Character.isLowerCase(prev)) {
- return true;
- }
- if (next == 0) { // end of string
- return false;
- }
- return Character.isLowerCase(next);
- }
-
-
- // ********** convert underscores to camel case **********
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "LargeProject"
- * Capitalize the first letter.
- */
- public static String convertUnderscoresToCamelCase(String underscoreString) {
- return convertUnderscoresToCamelCase(underscoreString, true);
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "LargeProject"
- * Capitalize the first letter.
- */
- public static char[] convertUnderscoresToCamelCase(char[] underscoreString) {
- return convertUnderscoresToCamelCase(underscoreString, true);
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static String convertUnderscoresToCamelCase(String underscoreString, boolean capitalizeFirstLetter) {
- int len = underscoreString.length();
- if (len == 0) {
- return underscoreString;
- }
- return new String(convertUnderscoresToCamelCase_(underscoreString.toCharArray(), capitalizeFirstLetter, len));
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static char[] convertUnderscoresToCamelCase(char[] underscoreString, boolean capitalizeFirstLetter) {
- int len = underscoreString.length;
- if (len == 0) {
- return underscoreString;
- }
- return convertUnderscoresToCamelCase_(underscoreString, capitalizeFirstLetter, len);
- }
-
- private static char[] convertUnderscoresToCamelCase_(char[] underscoreString, boolean capitalizeFirstLetter, int len) {
- StringBuilder sb = new StringBuilder(len);
- convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, sb);
- return convertToCharArray(sb);
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, StringBuffer sb) {
- int len = underscoreString.length();
- if (len != 0) {
- convertUnderscoresToCamelCaseOn_(underscoreString.toCharArray(), capitalizeFirstLetter, len, sb);
- }
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, StringBuffer sb) {
- int len = underscoreString.length;
- if (len != 0) {
- convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, sb);
- }
- }
-
- private static void convertUnderscoresToCamelCaseOn_(char[] underscoreString, boolean capitalizeFirstLetter, int len, StringBuffer sb) {
- char prev = 0;
- char c = 0;
- boolean first = true;
- for (int i = 0; i < len; i++) {
- prev = c;
- c = underscoreString[i];
- if (c == '_') {
- continue;
- }
- if (first) {
- first = false;
- sb.append(capitalizeFirstLetter ? Character.toUpperCase(c) : Character.toLowerCase(c));
- } else {
- sb.append((prev == '_') ? Character.toUpperCase(c) : Character.toLowerCase(c));
- }
- }
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, StringBuilder sb) {
- int len = underscoreString.length();
- if (len != 0) {
- convertUnderscoresToCamelCaseOn_(underscoreString.toCharArray(), capitalizeFirstLetter, len, sb);
- }
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, StringBuilder sb) {
- int len = underscoreString.length;
- if (len != 0) {
- convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, sb);
- }
- }
-
- private static void convertUnderscoresToCamelCaseOn_(char[] underscoreString, boolean capitalizeFirstLetter, int len, StringBuilder sb) {
- char prev = 0;
- char c = 0;
- boolean first = true;
- for (int i = 0; i < len; i++) {
- prev = c;
- c = underscoreString[i];
- if (c == '_') {
- continue;
- }
- if (first) {
- first = false;
- sb.append(capitalizeFirstLetter ? Character.toUpperCase(c) : Character.toLowerCase(c));
- } else {
- sb.append((prev == '_') ? Character.toUpperCase(c) : Character.toLowerCase(c));
- }
- }
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static void convertUnderscoresToCamelCaseOn(String underscoreString, boolean capitalizeFirstLetter, Writer writer) {
- int len = underscoreString.length();
- if (len != 0) {
- convertUnderscoresToCamelCaseOn_(underscoreString.toCharArray(), capitalizeFirstLetter, len, writer);
- }
- }
-
- /**
- * Convert the specified "underscore" string to a "camel case" string:
- * "LARGE_PROJECT" -> "largeProject"
- * Optionally capitalize the first letter.
- */
- public static void convertUnderscoresToCamelCaseOn(char[] underscoreString, boolean capitalizeFirstLetter, Writer writer) {
- int len = underscoreString.length;
- if (len != 0) {
- convertUnderscoresToCamelCaseOn_(underscoreString, capitalizeFirstLetter, len, writer);
- }
- }
-
- private static void convertUnderscoresToCamelCaseOn_(char[] underscoreString, boolean capitalizeFirstLetter, int len, Writer writer) {
- char prev = 0;
- char c = 0;
- boolean first = true;
- for (int i = 0; i < len; i++) {
- prev = c;
- c = underscoreString[i];
- if (c == '_') {
- continue;
- }
- if (first) {
- first = false;
- writeCharOn(capitalizeFirstLetter ? Character.toUpperCase(c) : Character.toLowerCase(c), writer);
- } else {
- writeCharOn((prev == '_') ? Character.toUpperCase(c) : Character.toLowerCase(c), writer);
- }
- }
- }
-
-
- // ********** convert to Java string literal **********
-
- public static final String EMPTY_JAVA_STRING_LITERAL = "\"\""; //$NON-NLS-1$
- public static final char[] EMPTY_JAVA_STRING_LITERAL_CHAR_ARRAY = EMPTY_JAVA_STRING_LITERAL.toCharArray();
-
- public static String convertToJavaStringLiteral(String string) {
- int len = string.length();
- if (len == 0) {
- return EMPTY_JAVA_STRING_LITERAL;
- }
- StringBuilder sb = new StringBuilder(len + 5);
- convertToJavaStringLiteralOn_(string.toCharArray(), sb, len);
- return sb.toString();
- }
-
- public static char[] convertToJavaStringLiteral(char[] string) {
- int len = string.length;
- if (len == 0) {
- return EMPTY_JAVA_STRING_LITERAL_CHAR_ARRAY;
- }
- StringBuilder sb = new StringBuilder(len + 5);
- convertToJavaStringLiteralOn_(string, sb, len);
- len = sb.length();
- char[] result = new char[len];
- sb.getChars(0, len, result, 0);
- return result;
- }
-
- public static Iterator<String> convertToJavaStringLiterals(Iterator<String> strings) {
- return new TransformationIterator<String, String>(strings) {
- @Override
- protected String transform(String string) {
- return StringTools.convertToJavaStringLiteral(string);
- }
- };
- }
-
- // cannot name method simply 'convertToJavaStringLiterals' because of type-erasure...
- public static Iterator<char[]> convertToJavaCharArrayLiterals(Iterator<char[]> strings) {
- return new TransformationIterator<char[], char[]>(strings) {
- @Override
- protected char[] transform(char[] string) {
- return StringTools.convertToJavaStringLiteral(string);
- }
- };
- }
-
- public static void convertToJavaStringLiteralOn(String string, StringBuffer sb) {
- int len = string.length();
- if (len == 0) {
- sb.append(EMPTY_JAVA_STRING_LITERAL);
- } else {
- convertToJavaStringLiteralOn_(string.toCharArray(), sb, len);
- }
- }
-
- public static void convertToJavaStringLiteralOn(char[] string, StringBuffer sb) {
- int len = string.length;
- if (len == 0) {
- sb.append(EMPTY_JAVA_STRING_LITERAL);
- } else {
- convertToJavaStringLiteralOn_(string, sb, len);
- }
- }
-
- /*
- * no length checks
- */
- private static void convertToJavaStringLiteralOn_(char[] string, StringBuffer sb, int len) {
- sb.ensureCapacity(sb.length() + len + 5);
- sb.append(QUOTE);
- for (char c : string) {
- switch (c) {
- case '\b': // backspace
- sb.append("\\b"); //$NON-NLS-1$
- break;
- case '\t': // horizontal tab
- sb.append("\\t"); //$NON-NLS-1$
- break;
- case '\n': // line-feed LF
- sb.append("\\n"); //$NON-NLS-1$
- break;
- case '\f': // form-feed FF
- sb.append("\\f"); //$NON-NLS-1$
- break;
- case '\r': // carriage-return CR
- sb.append("\\r"); //$NON-NLS-1$
- break;
- case '"': // double-quote
- sb.append("\\\""); //$NON-NLS-1$
- break;
-// case '\'': // single-quote
-// sb.append("\\'"); //$NON-NLS-1$
-// break;
- case '\\': // backslash
- sb.append("\\\\"); //$NON-NLS-1$
- break;
- default:
- sb.append(c);
- break;
- }
- }
- sb.append(QUOTE);
- }
-
- public static void convertToJavaStringLiteralOn(String string, StringBuilder sb) {
- int len = string.length();
- if (len == 0) {
- sb.append(EMPTY_JAVA_STRING_LITERAL);
- } else {
- convertToJavaStringLiteralOn_(string.toCharArray(), sb, len);
- }
- }
-
- public static void convertToJavaStringLiteralOn(char[] string, StringBuilder sb) {
- int len = string.length;
- if (len == 0) {
- sb.append(EMPTY_JAVA_STRING_LITERAL);
- } else {
- convertToJavaStringLiteralOn_(string, sb, len);
- }
- }
-
- /*
- * no length checks
- */
- private static void convertToJavaStringLiteralOn_(char[] string, StringBuilder sb, int len) {
- sb.ensureCapacity(sb.length() + len + 5);
- sb.append(QUOTE);
- for (char c : string) {
- switch (c) {
- case '\b': // backspace
- sb.append("\\b"); //$NON-NLS-1$
- break;
- case '\t': // horizontal tab
- sb.append("\\t"); //$NON-NLS-1$
- break;
- case '\n': // line-feed LF
- sb.append("\\n"); //$NON-NLS-1$
- break;
- case '\f': // form-feed FF
- sb.append("\\f"); //$NON-NLS-1$
- break;
- case '\r': // carriage-return CR
- sb.append("\\r"); //$NON-NLS-1$
- break;
- case '"': // double-quote
- sb.append("\\\""); //$NON-NLS-1$
- break;
-// case '\'': // single-quote
-// sb.append("\\'"); //$NON-NLS-1$
-// break;
- case '\\': // backslash
- sb.append("\\\\"); //$NON-NLS-1$
- break;
- default:
- sb.append(c);
- break;
- }
- }
- sb.append(QUOTE);
- }
-
- public static void convertToJavaStringLiteralOn(String string, Writer writer) {
- if (string.length() == 0) {
- writeStringOn(EMPTY_JAVA_STRING_LITERAL, writer);
- } else {
- convertToJavaStringLiteralOn_(string.toCharArray(), writer);
- }
- }
-
- public static void convertToJavaStringLiteralOn(char[] string, Writer writer) {
- if (string.length == 0) {
- writeStringOn(EMPTY_JAVA_STRING_LITERAL, writer);
- } else {
- convertToJavaStringLiteralOn_(string, writer);
- }
- }
-
- /*
- * no length checks
- */
- private static void convertToJavaStringLiteralOn_(char[] string, Writer writer) {
- writeCharOn(QUOTE, writer);
- for (char c : string) {
- switch (c) {
- case '\b': // backspace
- writeStringOn("\\b", writer); //$NON-NLS-1$
- break;
- case '\t': // horizontal tab
- writeStringOn("\\t", writer); //$NON-NLS-1$
- break;
- case '\n': // line-feed LF
- writeStringOn("\\n", writer); //$NON-NLS-1$
- break;
- case '\f': // form-feed FF
- writeStringOn("\\f", writer); //$NON-NLS-1$
- break;
- case '\r': // carriage-return CR
- writeStringOn("\\r", writer); //$NON-NLS-1$
- break;
- case '"': // double-quote
- writeStringOn("\\\"", writer); //$NON-NLS-1$
- break;
-// case '\'': // single-quote
-// writeStringOn("\\'", writer); //$NON-NLS-1$
-// break;
- case '\\': // backslash
- writeStringOn("\\\\", writer); //$NON-NLS-1$
- break;
- default:
- writeCharOn(c, writer);
- break;
- }
- }
- writeCharOn(QUOTE, writer);
- }
-
-
- // ********** convenience **********
-
- public static char[] convertToCharArray(StringBuffer sb) {
- int len = sb.length();
- char[] result = new char[len];
- sb.getChars(0, len, result, 0);
- return result;
- }
-
- public static char[] convertToCharArray(StringBuilder sb) {
- int len = sb.length();
- char[] result = new char[len];
- sb.getChars(0, len, result, 0);
- return result;
- }
-
- private static void writeStringOn(char[] string, Writer writer) {
- try {
- writer.write(string);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private static void writeStringOn(char[] string, char escape, Writer writer) {
- try {
- for (char c : string) {
- if (c == escape) {
- writer.write(c);
- }
- writer.write(c);
- }
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private static void writeStringOn(char[] string, int off, int len, Writer writer) {
- try {
- writer.write(string, off, len);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private static void writeStringOn(String string, int off, int len, Writer writer) {
- try {
- writer.write(string, off, len);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private static void writeStringOn(String string, Writer writer) {
- try {
- writer.write(string);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private static void writeCharOn(char c, Writer writer) {
- try {
- writer.write(c);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
-
- // ********** constructor **********
-
- /*
- * Suppress default constructor, ensuring non-instantiability.
- */
- private StringTools() {
- super();
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java
deleted file mode 100644
index 001aa64bd6..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedBoolean.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import org.eclipse.jpt.utility.Command;
-
-/**
- * This class provides synchronized access to a boolean value.
- * It also provides protocol for suspending a thread until the
- * boolean value is set to true or false, with optional time-outs.
- * @see BooleanHolder
- */
-public class SynchronizedBoolean
- implements Cloneable, Serializable
-{
- /** Backing boolean. */
- private boolean value;
-
- /** Object to synchronize on. */
- private final Object mutex;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Create a synchronized boolean with the specified initial value
- * and mutex.
- */
- public SynchronizedBoolean(boolean value, Object mutex) {
- super();
- this.value = value;
- this.mutex = mutex;
- }
-
- /**
- * Create a synchronized boolean with the specified initial value.
- */
- public SynchronizedBoolean(boolean value) {
- super();
- this.value = value;
- this.mutex = this;
- }
-
- /**
- * Create a synchronized boolean with an initial value of false
- * and specified mutex.
- */
- public SynchronizedBoolean(Object mutex) {
- this(false, mutex);
- }
-
- /**
- * Create a synchronized boolean with an initial value of false.
- */
- public SynchronizedBoolean() {
- this(false);
- }
-
-
- // ********** accessors **********
-
- /**
- * Return the current boolean value.
- */
- public boolean value() {
- synchronized (this.mutex) {
- return this.value;
- }
- }
-
- /**
- * Return whether the current boolean value is true.
- */
- public boolean isTrue() {
- synchronized (this.mutex) {
- return this.value;
- }
- }
-
- /**
- * Return whether the current boolean value is false.
- */
- public boolean isFalse() {
- synchronized (this.mutex) {
- return ! this.value;
- }
- }
-
- /**
- * Return whether the current boolean value is the specified value.
- */
- public boolean is(boolean v) {
- synchronized (this.mutex) {
- return this.value == v;
- }
- }
-
- /**
- * Set the boolean value. If the value changes, all waiting
- * threads are notified.
- */
- public void setValue(boolean value) {
- synchronized (this.mutex) {
- if (this.value != value) {
- this.value = value;
- this.mutex.notifyAll();
- }
- }
- }
-
- /**
- * Set the boolean value to true. If the value changes, all waiting
- * threads are notified.
- */
- public void setTrue() {
- synchronized (this.mutex) {
- this.setValue(true);
- }
- }
-
- /**
- * Set the boolean value to false. If the value changes, all waiting
- * threads are notified.
- */
- public void setFalse() {
- synchronized (this.mutex) {
- this.setValue(false);
- }
- }
-
- /**
- * Return the object this object locks on while performing
- * its operations.
- */
- public Object mutex() {
- return this.mutex;
- }
-
-
- // ********** indefinite waits **********
-
- /**
- * Suspend the current thread until the boolean value changes
- * to the specified value. If the boolean value is already the
- * specified value, return immediately.
- */
- public void waitUntilValueIs(boolean v) throws InterruptedException {
- synchronized (this.mutex) {
- while (this.value != v) {
- this.mutex.wait();
- }
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to true.
- * If the boolean value is already true, return immediately.
- */
- public void waitUntilTrue() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilValueIs(true);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to false.
- * If the boolean value is already false, return immediately.
- */
- public void waitUntilFalse() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilValueIs(false);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to
- * NOT the specified value, then change it back to the specified
- * value and continue executing. If the boolean value is already
- * NOT the specified value, set the value to the specified value
- * immediately.
- */
- public void waitToSetValue(boolean v) throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilValueIs( ! v);
- this.setValue(v);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to false,
- * then change it back to true and continue executing. If the boolean
- * value is already false, set the value to true immediately.
- */
- public void waitToSetTrue() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitToSetValue(true);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to true,
- * then change it back to false and continue executing. If the boolean
- * value is already true, set the value to false immediately.
- */
- public void waitToSetFalse() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitToSetValue(false);
- }
- }
-
-
- // ********** timed waits **********
-
- /**
- * Suspend the current thread until the boolean value changes
- * to the specified value or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- * If the boolean value is already the specified value, return true
- * immediately.
- */
- public boolean waitUntilValueIs(boolean v, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- if (timeout == 0L) {
- this.waitUntilValueIs(v); // wait indefinitely until notified
- return true; // if it ever comes back, the condition was met
- }
-
- long stop = System.currentTimeMillis() + timeout;
- long remaining = timeout;
- while ((this.value != v) && (remaining > 0L)) {
- this.mutex.wait(remaining);
- remaining = stop - System.currentTimeMillis();
- }
- return (this.value == v);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes
- * to true or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- * If the boolean value is already true, return true immediately.
- */
- public boolean waitUntilTrue(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilValueIs(true, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes
- * to false or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- * If the boolean value is already true, return true immediately.
- */
- public boolean waitUntilFalse(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilValueIs(false, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to NOT the
- * specified value, then change it back to the specified value and continue
- * executing. If the boolean value does not change to false before the
- * time-out, simply continue executing without changing the value.
- * The time-out is specified in milliseconds. Return true if the value was
- * set to the specified value; return false if a time-out occurred.
- * If the boolean value is already NOT the specified value, set the value
- * to the specified value immediately and return true.
- */
- public boolean waitToSetValue(boolean v, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- boolean success = this.waitUntilValueIs( ! v, timeout);
- if (success) {
- this.setValue(v);
- }
- return success;
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to false,
- * then change it back to true and continue executing. If the boolean
- * value does not change to false before the time-out, simply continue
- * executing without changing the value. The time-out is specified in
- * milliseconds. Return true if the value was set to true; return false
- * if a time-out occurred. If the boolean value is already false, set the
- * value to true immediately and return true.
- */
- public boolean waitToSetTrue(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitToSetValue(true, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the boolean value changes to true,
- * then change it back to false and continue executing. If the boolean
- * value does not change to true before the time-out, simply continue
- * executing without changing the value. The time-out is specified in
- * milliseconds. Return true if the value was set to false; return false
- * if a time-out occurred. If the boolean value is already true, set the
- * value to false immediately and return true.
- */
- public boolean waitToSetFalse(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitToSetValue(false, timeout);
- }
- }
-
-
- // ********** synchronized behavior **********
-
- /**
- * If the current thread is not interrupted, execute the specified command
- * with the mutex locked. This is useful for initializing the value in another
- * thread.
- */
- public void execute(Command command) throws InterruptedException {
- if (Thread.interrupted()) {
- throw new InterruptedException();
- }
- synchronized (this.mutex) {
- command.execute();
- }
- }
-
-
- // ********** standard methods **********
-
- @Override
- public Object clone() {
- try {
- synchronized (this.mutex) {
- return super.clone();
- }
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof SynchronizedBoolean) {
- return this.value() == ((SynchronizedBoolean) o).value();
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return this.value() ? 1 : 0;
- }
-
- @Override
- public String toString() {
- return String.valueOf(this.value());
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java
deleted file mode 100644
index bcf83dbfa9..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedObject.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import org.eclipse.jpt.utility.Command;
-
-/**
- * This class provides synchronized access to an object of type T.
- * It also provides protocol for suspending a thread until the
- * value is set to null or a non-null value, with optional time-outs.
- */
-public class SynchronizedObject<T>
- implements Cloneable, Serializable
-{
- /** Backing value. */
- private T value;
-
- /** Object to synchronize on. */
- private final Object mutex;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Create a synchronized object with the specified initial value
- * and mutex.
- */
- public SynchronizedObject(T value, Object mutex) {
- super();
- this.value = value;
- this.mutex = mutex;
- }
-
- /**
- * Create a synchronized object with the specified initial value.
- */
- public SynchronizedObject(T value) {
- super();
- this.value = value;
- this.mutex = this;
- }
-
- /**
- * Create a synchronized object with an initial value of null.
- */
- public SynchronizedObject() {
- this(null);
- }
-
-
- // ********** accessors **********
-
- /**
- * Return the current value.
- */
- public T value() {
- synchronized (this.mutex) {
- return this.value;
- }
- }
-
- /**
- * Return whether the current value is null.
- */
- public boolean isNull() {
- synchronized (this.mutex) {
- return this.value == null;
- }
- }
-
- /**
- * Return whether the current value is not null.
- */
- public boolean isNotNull() {
- synchronized (this.mutex) {
- return this.value != null;
- }
- }
-
- /**
- * Set the value. If the value changes, all waiting
- * threads are notified.
- */
- public void setValue(T value) {
- synchronized (this.mutex) {
- if (this.value != value) {
- this.value = value;
- this.mutex.notifyAll();
- }
- }
- }
-
- /**
- * Set the value to null. If the value changes, all waiting
- * threads are notified.
- */
- public void setNull() {
- synchronized (this.mutex) {
- this.setValue(null);
- }
- }
-
- /**
- * Return the object this object locks on while performing
- * its operations.
- */
- public Object mutex() {
- return this.mutex;
- }
-
-
- // ********** indefinite waits **********
-
- /**
- * Suspend the current thread until the value changes
- * to the specified value. If the value is already the
- * specified value, return immediately.
- */
- public void waitUntilValueIs(T v) throws InterruptedException {
- synchronized (this.mutex) {
- while (this.value != v) {
- this.mutex.wait();
- }
- }
- }
-
- /**
- * Suspend the current thread until the value changes
- * to something other than the specified value. If the
- * value is already NOT the specified value, return immediately.
- */
- public void waitUntilValueIsNot(T v) throws InterruptedException {
- synchronized (this.mutex) {
- while (this.value == v) {
- this.mutex.wait();
- }
- }
- }
-
- /**
- * Suspend the current thread until the value changes to null.
- * If the value is already null, return immediately.
- */
- public void waitUntilNull() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilValueIs(null);
- }
- }
-
- /**
- * Suspend the current thread until the value changes
- * to something other than null.
- * If the value is already NOT null, return immediately.
- */
- public void waitUntilNotNull() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilValueIsNot(null);
- }
- }
-
- /**
- * Suspend the current thread until the value changes to
- * something other than the specified value, then change
- * it back to the specified value and continue executing.
- * If the value is already NOT the specified value, set
- * the value immediately.
- */
- public void waitToSetValue(T v) throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilValueIsNot(v);
- this.setValue(v);
- }
- }
-
- /**
- * Suspend the current thread until the value changes to
- * something other than null, then change it back to null
- * and continue executing. If the value is already NOT null,
- * set the value to null immediately.
- */
- public void waitToSetNull() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilNotNull();
- this.setValue(null);
- }
- }
-
-
- // ********** timed waits **********
-
- /**
- * Suspend the current thread until the value changes
- * to the specified value or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- * If the value is already the specified value, return true immediately.
- */
- public boolean waitUntilValueIs(T v, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- if (timeout == 0L) {
- this.waitUntilValueIs(v); // wait indefinitely until notified
- return true; // if it ever comes back, the condition was met
- }
-
- long stop = System.currentTimeMillis() + timeout;
- long remaining = timeout;
- while ((this.value != v) && (remaining > 0L)) {
- this.mutex.wait(remaining);
- remaining = stop - System.currentTimeMillis();
- }
- return (this.value == v);
- }
- }
-
- /**
- * Suspend the current thread until the value changes to something
- * other than the specified value or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was removed; return false if a time-out occurred.
- * If the value is already NOT the specified value, return true immediately.
- */
- public boolean waitUntilValueIsNot(T v, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- if (timeout == 0L) {
- this.waitUntilValueIsNot(v); // wait indefinitely until notified
- return true; // if it ever comes back, the condition was met
- }
-
- long stop = System.currentTimeMillis() + timeout;
- long remaining = timeout;
- while ((this.value == v) && (remaining > 0L)) {
- this.mutex.wait(remaining);
- remaining = stop - System.currentTimeMillis();
- }
- return (this.value != v);
- }
- }
-
- /**
- * Suspend the current thread until the value changes
- * to null or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- * If the value is already null, return true immediately.
- */
- public boolean waitUntilNull(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilValueIs(null, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the value changes
- * to something other than null or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- * If the value is already NOT null, return true immediately.
- */
- public boolean waitUntilNotNull(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilValueIsNot(null, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the value changes to
- * something other than the specified value, then change
- * it back to the specified value and continue executing.
- * If the value does not change to something other than the
- * specified before the time-out, simply continue executing
- * without changing the value.
- * The time-out is specified in milliseconds. Return true if the value was
- * set to true; return false if a time-out occurred.
- * If the value is already something other than the specified value, set
- * the value immediately and return true.
- */
- public boolean waitToSetValue(T v, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- boolean success = this.waitUntilValueIsNot(v, timeout);
- if (success) {
- this.setValue(v);
- }
- return success;
- }
- }
-
- /**
- * Suspend the current thread until the value changes to something
- * other than null, then change it back to null and continue executing.
- * If the value does not change to something other than null before
- * the time-out, simply continue executing without changing the value.
- * The time-out is specified in milliseconds. Return true if the value was
- * set to false; return false if a time-out occurred.
- * If the value is already something other than null, set
- * the value to null immediately and return true.
- */
- public boolean waitToSetNull(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- boolean success = this.waitUntilNotNull(timeout);
- if (success) {
- this.setValue(null);
- }
- return success;
- }
- }
-
-
- // ********** synchronized behavior **********
-
- /**
- * If current thread is not interrupted, execute the specified command
- * with the mutex locked. This is useful for initializing the value in another
- * thread.
- */
- public void execute(Command command) throws InterruptedException {
- if (Thread.interrupted()) {
- throw new InterruptedException();
- }
- synchronized (this.mutex) {
- command.execute();
- }
- }
-
-
- // ********** standard methods **********
-
- @Override
- public SynchronizedObject<T> clone() {
- try {
- synchronized (this.mutex) {
- @SuppressWarnings("unchecked")
- SynchronizedObject<T> clone = (SynchronizedObject<T>) super.clone();
- return clone;
- }
- } catch (CloneNotSupportedException ex) {
- throw new InternalError();
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if ( ! (obj instanceof SynchronizedObject)) {
- return false;
- }
- Object v1 = this.value();
- Object v2 = ((SynchronizedObject<?>) obj).value();
- return (v1 == null) ?
- (v2 == null) : v1.equals(v2);
- }
-
- @Override
- public int hashCode() {
- Object v = this.value();
- return (v == null) ? 0 : v.hashCode();
- }
-
- @Override
- public String toString() {
- return String.valueOf(this.value());
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
deleted file mode 100644
index e232c402ff..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.Serializable;
-import java.util.EmptyStackException;
-import org.eclipse.jpt.utility.Command;
-
-/**
- * Thread-safe implementation of the Stack interface.
- * This also provides protocol for suspending a thread until the
- * stack is empty or not empty, with optional time-outs.
- */
-public class SynchronizedStack<E>
- implements Stack<E>, Serializable
-{
- /** Backing stack. */
- private Stack<E> stack;
-
- /** Object to synchronize on. */
- private final Object mutex;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a synchronized stack that wraps the
- * specified stack and locks on the specified mutex.
- */
- public SynchronizedStack(Stack<E> stack, Object mutex) {
- super();
- this.stack = stack;
- this.mutex = mutex;
- }
-
- /**
- * Construct a synchronized stack that wraps the
- * specified stack and locks on itself.
- */
- public SynchronizedStack(Stack<E> stack) {
- super();
- this.stack = stack;
- this.mutex = this;
- }
-
- /**
- * Construct a synchronized stack that locks on the specified mutex.
- */
- public SynchronizedStack(Object mutex) {
- this(new SimpleStack<E>(), mutex);
- }
-
- /**
- * Construct a synchronized stack that locks on itself.
- */
- public SynchronizedStack() {
- this(new SimpleStack<E>());
- }
-
-
- // ********** Stack implementation **********
-
- public void push(E o) {
- synchronized (this.mutex) {
- this.stack.push(o);
- this.mutex.notifyAll();
- }
- }
-
- public E pop() {
- synchronized (this.mutex) {
- E o = this.stack.pop();
- this.mutex.notifyAll();
- return o;
- }
- }
-
- public E peek() {
- synchronized (this.mutex) {
- return this.stack.peek();
- }
- }
-
- public boolean isEmpty() {
- synchronized (this.mutex) {
- return this.stack.isEmpty();
- }
- }
-
-
- // ********** indefinite waits **********
-
- /**
- * Suspend the current thread until the stack's empty status changes
- * to the specified value.
- */
- public void waitUntilEmptyIs(boolean empty) throws InterruptedException {
- synchronized (this.mutex) {
- while (this.isEmpty() != empty) {
- this.mutex.wait();
- }
- }
- }
-
- /**
- * Suspend the current thread until the stack is empty.
- */
- public void waitUntilEmpty() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmptyIs(true);
- }
- }
-
- /**
- * Suspend the current thread until the stack has something on it.
- */
- public void waitUntilNotEmpty() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmptyIs(false);
- }
- }
-
- /**
- * Suspend the current thread until the stack is empty,
- * then "push" the specified item on to the top of the stack
- * and continue executing.
- */
- public void waitToPush(E o) throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmpty();
- this.push(o);
- }
- }
-
- /**
- * Suspend the current thread until the stack has something on it,
- * then "pop" an item from the top of the stack and return it.
- */
- public Object waitToPop() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilNotEmpty();
- return this.pop();
- }
- }
-
-
- // ********** timed waits **********
-
- /**
- * Suspend the current thread until the stack's empty status changes
- * to the specified value or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
- */
- public boolean waitUntilEmptyIs(boolean empty, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- if (timeout == 0L) {
- this.waitUntilEmptyIs(empty); // wait indefinitely until notified
- return true; // if it ever comes back, the condition was met
- }
-
- long stop = System.currentTimeMillis() + timeout;
- long remaining = timeout;
- while ((this.isEmpty() != empty) && (remaining > 0L)) {
- this.mutex.wait(remaining);
- remaining = stop - System.currentTimeMillis();
- }
- return (this.isEmpty() == empty);
- }
- }
-
- /**
- * Suspend the current thread until the stack is empty
- * or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if
- * the stack is empty; return false if a time-out occurred.
- */
- public boolean waitUntilEmpty(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilEmptyIs(true, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the stack has something on it.
- * or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if
- * the stack has something on it; return false if a time-out occurred.
- */
- public boolean waitUntilNotEmpty(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilEmptyIs(false, timeout);
- }
- }
-
- /**
- * Suspend the current thread until the stack is empty,
- * then "push" the specified item on to the top of the stack
- * and continue executing. If the stack is not emptied out
- * before the time-out, simply continue executing without
- * "pushing" the item.
- * The time-out is specified in milliseconds. Return true if the
- * item was pushed; return false if a time-out occurred.
- */
- public boolean waitToPush(E o, long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- boolean success = this.waitUntilEmpty(timeout);
- if (success) {
- this.push(o);
- }
- return success;
- }
- }
-
- /**
- * Suspend the current thread until the stack has something on it,
- * then "pop" an item from the top of the stack and return it.
- * If the stack is empty and nothing is "pushed" on to it before the
- * time-out, throw an empty stack exception.
- * The time-out is specified in milliseconds.
- */
- public Object waitToPop(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- boolean success = this.waitUntilNotEmpty(timeout);
- if (success) {
- return this.pop();
- }
- throw new EmptyStackException();
- }
- }
-
-
- // ********** synchronized behavior **********
-
- /**
- * If the current thread is not interrupted, execute the specified command
- * with the mutex locked. This is useful for initializing the stack in another
- * thread.
- */
- public void execute(Command command) throws InterruptedException {
- if (Thread.interrupted()) {
- throw new InterruptedException();
- }
- synchronized (this.mutex) {
- command.execute();
- }
- }
-
-
- // ********** additional public protocol **********
-
- /**
- * Return the object this object locks on while performing
- * its operations.
- */
- public Object mutex() {
- return this.mutex;
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- synchronized (this.mutex) {
- return this.stack.toString();
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Transformer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Transformer.java
deleted file mode 100644
index 75e4cc0839..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Transformer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-/**
- * Used by various "pluggable" classes to transform objects.
- * Transform an object of type T1 to an object of type T2.
- */
-public interface Transformer<T1, T2> {
-
- /**
- * Return the transformed object.
- * The semantics of "transform" is determined by the
- * contract between the client and the server.
- */
- T2 transform(T1 o);
-
-
- final class Null<S1, S2> implements Transformer<S1, S2> {
- @SuppressWarnings("unchecked")
- public static final Transformer INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R1, R2> Transformer<R1, R2> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // simply return the object, unchanged
- @SuppressWarnings("unchecked")
- public S2 transform(S1 o) {
- return (S2) o;
- }
- @Override
- public String toString() {
- return "Transformer.Null";
- }
- }
-
- final class Disabled<S1, S2> implements Transformer<S1, S2> {
- @SuppressWarnings("unchecked")
- public static final Transformer INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R1, R2> Transformer<R1, R2> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public S2 transform(S1 o) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "Transformer.Disabled";
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/XMLStringEncoder.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/XMLStringEncoder.java
deleted file mode 100644
index fcc359de00..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/XMLStringEncoder.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-
-/**
- * This encoder will replace any of a specified set of characters with an XML
- * "character reference": '/' => "&#x2f;"
- */
-public final class XMLStringEncoder {
-
- /** The set of characters to be converted into XML character references. */
- private final char[] chars;
-
- /** Cache the value of the highest character in the set above. */
- private final char maxChar;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct an encoder that converts the specified set of characters
- * into XML character references.
- */
- public XMLStringEncoder(char[] chars) {
- super();
- if (chars == null) {
- throw new NullPointerException();
- }
- // the ampersand must be included since it is the escape character
- if (CollectionTools.contains(chars, '&')) {
- this.chars = chars;
- } else {
- this.chars = CollectionTools.add(chars, '&');
- }
- this.maxChar = this.calculateMaxInvalidFileNameChar();
- }
-
- /**
- * Calculate the maximum value of the set of characters to be converted
- * into XML character references. This will be used to short-circuit the
- * search for a character in the set.
- * @see #charIsToBeEncoded(char)
- */
- private char calculateMaxInvalidFileNameChar() {
- char[] localChars = this.chars;
- char max = 0;
- for (int i = localChars.length; i-- > 0; ) {
- char c = localChars[i];
- if (max < c) {
- max = c;
- }
- }
- return max;
- }
-
-
- // ********** API **********
-
- /**
- * Return the specified string with any characters in the set
- * replaced with XML character references.
- */
- public String encode(String s) {
- int len = s.length();
- // allow for a few encoded characters
- StringBuilder sb = new StringBuilder(len + 20);
- for (int i = 0; i < len; i++) {
- this.appendCharacterTo(s.charAt(i), sb);
- }
- return sb.toString();
- }
-
- /**
- * Return the specified string with any XML character references
- * replaced by the characters themselves.
- */
- public String decode(String s) {
- StringBuilder sb = new StringBuilder(s.length());
- StringBuilder temp = new StringBuilder(); // performance tweak
- this.decodeTo(new StringReader(s), sb, temp);
- return sb.toString();
- }
-
-
- // ********** internal methods **********
-
- /**
- * Append the specified character to the string buffer,
- * converting it to an XML character reference if necessary.
- */
- private void appendCharacterTo(char c, StringBuilder sb) {
- if (this.charIsToBeEncoded(c)) {
- this.appendCharacterReferenceTo(c, sb);
- } else {
- sb.append(c);
- }
- }
-
- /**
- * Return whether the specified character is one of the characters
- * to be converted to XML character references.
- */
- private boolean charIsToBeEncoded(char c) {
- return (c <= this.maxChar) && CollectionTools.contains(this.chars, c);
- }
-
- /**
- * Append the specified character's XML character reference to the
- * specified string buffer (e.g. '/' => "&#x2f;").
- */
- private void appendCharacterReferenceTo(char c, StringBuilder sb) {
- sb.append("&#x");
- sb.append(Integer.toString(c, 16));
- sb.append(';');
- }
-
- private void decodeTo(Reader reader, StringBuilder sb, StringBuilder temp) {
- try {
- this.decodeTo_(reader, sb, temp);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private void decodeTo_(Reader reader, StringBuilder sb, StringBuilder temp) throws IOException {
- int c = reader.read();
- while (c != -1) {
- if (c == '&') {
- this.decodeCharacterReferenceTo(reader, sb, temp);
- } else {
- sb.append((char) c);
- }
- c = reader.read();
- }
- reader.close();
- }
-
- private void decodeCharacterReferenceTo(Reader reader, StringBuilder sb, StringBuilder temp) throws IOException {
- int c = reader.read();
- this.checkChar(c, '#');
- c = reader.read();
- this.checkChar(c, 'x');
-
- temp.setLength(0); // re-use temp
- c = reader.read();
- while (c != ';') {
- this.checkEndOfStream(c);
- temp.append((char) c);
- c = reader.read();
- }
- String charValue = temp.toString();
- if (charValue.length() == 0) {
- throw new IllegalStateException("missing numeric string");
- }
- sb.append((char) Integer.parseInt(charValue, 16));
- }
-
- private void checkChar(int c, int expected) {
- this.checkEndOfStream(c);
- if (c != expected) {
- throw new IllegalStateException("expected '" + (char) expected + "', but encountered '" + (char) c + "'");
- }
- }
-
- private void checkEndOfStream(int c) {
- if (c == -1) {
- throw new IllegalStateException("unexpected end of string");
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java
deleted file mode 100644
index 2874af48ad..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * An <code>ArrayIterator</code> provides an <code>Iterator</code>
- * for an array of objects of type E.
- */
-public class ArrayIterator<E>
- implements Iterator<E>
-{
- final E[] array; // private-protected
- int nextIndex; // private-protected
- private final int maxIndex;
-
- /**
- * Construct an iterator for the specified array.
- */
- public ArrayIterator(E... array) {
- this(array, 0, array.length);
- }
-
- /**
- * Construct an iterator for the specified array,
- * starting at the specified start index and continuing for
- * the specified length.
- */
- public ArrayIterator(E[] array, int start, int length) {
- if ((start < 0) || (start > array.length)) {
- throw new IllegalArgumentException("start: " + start);
- }
- if ((length < 0) || (length > array.length - start)) {
- throw new IllegalArgumentException("length: " + length);
- }
- this.array = array;
- this.nextIndex = start;
- this.maxIndex = start + length;
- }
-
- public boolean hasNext() {
- return this.nextIndex < this.maxIndex;
- }
-
- public E next() {
- if (this.hasNext()) {
- return this.array[this.nextIndex++];
- }
- throw new NoSuchElementException();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, CollectionTools.list(this.array));
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java
deleted file mode 100644
index 5b70ed4721..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-
-/**
- * An <code>ArrayListIterator</code> provides a <code>ListIterator</code>
- * for an array of objects.
- *
- * The name might be a bit confusing:
- * This is a <code>ListIterator</code> for an <code>Array</code>;
- * <em>not</em> an <code>Iterator</code> for an <code>ArrayList</code>.
- */
-public class ArrayListIterator<E>
- extends ArrayIterator<E>
- implements ListIterator<E>
-{
- private final int minIndex;
-
- /**
- * Construct a list iterator for the specified array.
- */
- public ArrayListIterator(E... array) {
- this(array, 0, array.length);
- }
-
- /**
- * Construct a list iterator for the specified array,
- * starting at the specified start index and continuing for
- * the specified length.
- */
- public ArrayListIterator(E[] array, int start, int length) {
- super(array, start, length);
- this.minIndex = start;
- }
-
- public int nextIndex() {
- return this.nextIndex;
- }
-
- public int previousIndex() {
- return this.nextIndex - 1;
- }
-
- public boolean hasPrevious() {
- return this.nextIndex > this.minIndex;
- }
-
- public E previous() {
- if (this.hasPrevious()) {
- return this.array[--this.nextIndex];
- }
- throw new NoSuchElementException();
- }
-
- public void add(E e) {
- throw new UnsupportedOperationException();
- }
-
- public void set(E e) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return super.toString();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ChainIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ChainIterator.java
deleted file mode 100644
index ea5076e854..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ChainIterator.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>ChainIterator</code> provides a pluggable <code>Iterator</code>
- * that loops over a chain of arbitrarily linked objects. The chain
- * should be null-terminated (i.e. a call to the <code>nextLink(Object)</code>
- * method should return <code>null</code> when it is passed the last
- * link of the chain).
- * To use, supply a starting link and supply a <code>Linker</code> or
- * subclass <code>ChainIterator</code> and override the
- * <code>nextLink(Object)</code> method.
- * The starting link will be the first object returned by the iterator.
- * If the starting link is <code>null</code>, the iterator will be empty.
- * Note that the iterator does not support <code>null</code> elements.
- */
-public class ChainIterator<E>
- implements Iterator<E>
-{
- private E nextLink;
- private final Linker<E> linker;
-
-
- /**
- * Construct an iterator with the specified starting link
- * and a disabled linker.
- * Use this constructor if you want to override the
- * <code>nextLink(Object)</code> method instead of building
- * a <code>Linker</code>.
- */
- public ChainIterator(E startLink) {
- this(startLink, Linker.Disabled.<E>instance());
- }
-
- /**
- * Construct an iterator with the specified starting link
- * and linker.
- */
- public ChainIterator(E startLink, Linker<E> linker) {
- super();
- this.nextLink = startLink;
- this.linker = linker;
- }
-
- public boolean hasNext() {
- return this.nextLink != null;
- }
-
- public E next() {
- if (this.nextLink == null) {
- throw new NoSuchElementException();
- }
- E result = this.nextLink;
- this.nextLink = this.nextLink(this.nextLink);
- return result;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Return the next link in the chain.
- */
- protected E nextLink(E currentLink) {
- return this.linker.nextLink(currentLink);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nextLink);
- }
-
-
- //********** inner classes **********
-
- /**
- * Used by <code>ChainIterator</code> to link
- * the elements in the chain.
- */
- public interface Linker<T> {
-
- /**
- * Return the next link in the chain.
- */
- T nextLink(T currentLink);
-
-
- final class Null<S> implements Linker<S> {
- @SuppressWarnings("unchecked")
- public static final Linker INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R> Linker<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // simply return null, indicating the chain is ended
- public S nextLink(S currentLink) {
- return null;
- }
- @Override
- public String toString() {
- return "ChainIterator.Linker.Null";
- }
- }
-
- final class Disabled<S> implements Linker<S> {
- @SuppressWarnings("unchecked")
- public static final Linker INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> Linker<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public S nextLink(S currentLink) {
- throw new UnsupportedOperationException(); // ChainIterator.nextLink(Object) was not implemented
- }
- @Override
- public String toString() {
- return "ChainIterator.Linker.Disabled";
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java
deleted file mode 100644
index 7976439a03..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>CloneIterator</code> iterates over a copy of a collection,
- * allowing for concurrent access to the original collection.
- * <p>
- * The original collection passed to the <code>CloneIterator</code>'s
- * constructor should be synchronized; otherwise you run the risk of
- * a corrupted collection.
- * <p>
- * By default, a <code>CloneIterator</code> does not support the
- * <code>#remove()</code> operation; this is because it does not have
- * access to the original collection. But if the <code>CloneIterator</code>
- * is supplied with an <code>Mutator</code> it will delegate the
- * <code>#remove()</code> operation to the <code>Mutator</code>.
- * Alternatively, a subclass can override the <code>#remove(Object)</code>
- * method.
- */
-public class CloneIterator<E>
- implements Iterator<E>
-{
- private final Iterator<Object> nestedIterator;
- private E current;
- private final Mutator<E> mutator;
- private boolean removeAllowed;
-
-
- // ********** constructors **********
-
- /**
- * Construct an iterator on a copy of the specified collection.
- * The <code>#remove()</code> method will not be supported,
- * unless a subclass overrides the <code>#remove(Object)</code>.
- */
- public CloneIterator(Collection<? extends E> c) {
- this(c, Mutator.ReadOnly.<E>instance());
- }
-
- /**
- * Construct an iterator on a copy of the specified collection.
- * Use the specified mutator to remove objects from the
- * original collection.
- */
- public CloneIterator(Collection<? extends E> c, Mutator<E> mutator) {
- super();
- this.nestedIterator = new ArrayIterator<Object>(c.toArray());
- this.current = null;
- this.mutator = mutator;
- this.removeAllowed = false;
- }
-
-
- // ********** Iterator implementation **********
-
- public boolean hasNext() {
- return this.nestedIterator.hasNext();
- }
-
- public E next() {
- this.current = this.nestedNext();
- this.removeAllowed = true;
- return this.current;
- }
-
- public void remove() {
- if ( ! this.removeAllowed) {
- throw new IllegalStateException();
- }
- this.remove(this.current);
- this.removeAllowed = false;
- }
-
-
- // ********** internal methods **********
-
- /**
- * The collection passed in during construction held Es,
- * so this cast is not a problem. We need this cast because
- * all the elements of the original collection were copied into
- * an object array (Object[]).
- */
- @SuppressWarnings("unchecked")
- protected E nestedNext() {
- return (E) this.nestedIterator.next();
- }
-
- /**
- * Remove the specified element from the original collection.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building an <code>Mutator</code>.
- */
- protected void remove(E e) {
- this.mutator.remove(e);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-
- //********** member interface **********
-
- /**
- * Used by <code>CloneIterator</code> to remove
- * elements from the original collection; since the iterator
- * does not have direct access to the original collection.
- */
- public interface Mutator<T> {
-
- /**
- * Remove the specified object from the original collection.
- */
- void remove(T current);
-
-
- final class ReadOnly<S> implements Mutator<S> {
- @SuppressWarnings("unchecked")
- public static final Mutator INSTANCE = new ReadOnly();
- @SuppressWarnings("unchecked")
- public static <R> Mutator<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private ReadOnly() {
- super();
- }
- // remove is not supported
- public void remove(Object current) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "CloneIterator.Mutator.ReadOnly"; //$NON-NLS-1$
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java
deleted file mode 100644
index c4b5837ba1..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneListIterator.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>CloneListIterator</code> iterates over a copy of a list,
- * allowing for concurrent access to the original list.
- * <p>
- * The original list passed to the <code>CloneListIterator</code>'s
- * constructor should be synchronized; otherwise you run the risk of
- * a corrupted list.
- * <p>
- * By default, a <code>CloneListIterator</code> does not support the
- * modification operations; this is because it does not have
- * access to the original list. But if the <code>CloneListIterator</code>
- * is supplied with a <code>Mutator</code> it will delegate the
- * modification operations to the <code>Mutator</code>.
- * Alternatively, a subclass can override the modification methods.
- */
-public class CloneListIterator<E>
- implements ListIterator<E>
-{
- private final ListIterator<Object> nestedListIterator;
- private int cursor;
- private String state;
- private final Mutator<E> mutator;
-
- private static final String UNKNOWN = "unknown";
- private static final String PREVIOUS = "previous";
- private static final String NEXT = "next";
-
-
- // ********** constructors **********
-
- /**
- * Construct a list iterator on a copy of the specified list.
- * The modification methods will not be supported,
- * unless a subclass overrides them.
- */
- public CloneListIterator(List<? extends E> list) {
- this(list, Mutator.ReadOnly.<E>instance());
- }
-
- /**
- * Construct a list iterator on a copy of the specified list.
- * Use the specified list mutator to modify the original list.
- */
- public CloneListIterator(List<? extends E> list, Mutator<E> mutator) {
- super();
- // build a copy of the list and keep it in synch with original (if the mutator allows changes)
- // that way the nested list iterator will maintain some of our state
- this.nestedListIterator = CollectionTools.list(list.toArray()).listIterator();
- this.mutator = mutator;
- this.cursor = 0;
- this.state = UNKNOWN;
- }
-
-
- // ********** ListIterator implementation **********
-
- public boolean hasNext() {
- return this.nestedListIterator.hasNext();
- }
-
- public E next() {
- // allow the nested iterator to throw an exception before we modify the index
- E next = this.nestedNext();
- this.cursor++;
- this.state = NEXT;
- return next;
- }
-
- public void remove() {
- // allow the nested iterator to throw an exception before we modify the original list
- this.nestedListIterator.remove();
- if (this.state == PREVIOUS) {
- this.remove(this.cursor);
- } else {
- this.cursor--;
- this.remove(this.cursor);
- }
- }
-
- public int nextIndex() {
- return this.nestedListIterator.nextIndex();
- }
-
- public int previousIndex() {
- return this.nestedListIterator.previousIndex();
- }
-
- public boolean hasPrevious() {
- return this.nestedListIterator.hasPrevious();
- }
-
- public E previous() {
- // allow the nested iterator to throw an exception before we modify the index
- E previous = this.nestedPrevious();
- this.cursor--;
- this.state = PREVIOUS;
- return previous;
- }
-
- public void add(E o) {
- // allow the nested iterator to throw an exception before we modify the original list
- this.nestedListIterator.add(o);
- this.add(this.cursor, o);
- this.cursor++;
- }
-
- public void set(E o) {
- // allow the nested iterator to throw an exception before we modify the original list
- this.nestedListIterator.set(o);
- if (this.state == PREVIOUS) {
- this.set(this.cursor, o);
- } else {
- this.set(this.cursor - 1, o);
- }
- }
-
-
- // ********** internal methods **********
-
- /**
- * The list passed in during construction held Es,
- * so this cast is not a problem. We need this cast because
- * all the elements of the original collection were copied into
- * an object array (Object[]).
- */
- @SuppressWarnings("unchecked")
- protected E nestedNext() {
- return (E) this.nestedListIterator.next();
- }
-
- /**
- * The list passed in during construction held Es,
- * so this cast is not a problem. We need this cast because
- * all the elements of the original collection were copied into
- * an object array (Object[]).
- */
- @SuppressWarnings("unchecked")
- protected E nestedPrevious() {
- return (E) this.nestedListIterator.previous();
- }
-
- /**
- * Add the specified element to the original list.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Mutator</code>.
- */
- protected void add(int index, E o) {
- this.mutator.add(index, o);
- }
-
- /**
- * Remove the specified element from the original list.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Mutator</code>.
- */
- protected void remove(int index) {
- this.mutator.remove(index);
- }
-
- /**
- * Set the specified element in the original list.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Mutator</code>.
- */
- protected void set(int index, E o) {
- this.mutator.set(index, o);
- }
-
-
- // ********** overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-
- //********** member interface **********
-
- /**
- * Used by <code>CloneListIterator</code> to remove
- * elements from the original list; since the list iterator
- * does not have direct access to the original list.
- */
- public interface Mutator<T> {
-
- /**
- * Add the specified object to the original list.
- */
- void add(int index, T o);
-
- /**
- * Remove the specified object from the original list.
- */
- void remove(int index);
-
- /**
- * Set the specified object in the original list.
- */
- void set(int index, T o);
-
-
- final class ReadOnly<S> implements Mutator<S> {
- @SuppressWarnings("unchecked")
- public static final Mutator INSTANCE = new ReadOnly();
- @SuppressWarnings("unchecked")
- public static <R> Mutator<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private ReadOnly() {
- super();
- }
- // add is not supported
- public void add(int index, Object o) {
- throw new UnsupportedOperationException();
- }
- // remove is not supported
- public void remove(int index) {
- throw new UnsupportedOperationException();
- }
- // set is not supported
- public void set(int index, Object o) {
- throw new UnsupportedOperationException();
- }
- @Override
- public String toString() {
- return "CloneListIterator.Mutator.ReadOnly";
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeIterator.java
deleted file mode 100644
index 083f535b4a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeIterator.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>CompositeIterator</code> wraps a collection
- * of <code>Iterator</code>s and makes them appear to be a single
- * <code>Iterator</code>.
- */
-public class CompositeIterator<E>
- implements Iterator<E>
-{
- private final Iterator<? extends Iterator<? extends E>> iterators;
- private Iterator<? extends E> currentIterator;
- private Iterator<? extends E> lastIteratorToReturnNext;
-
-
- // ********** constructors **********
-
- /**
- * Construct an iterator with the specified collection of iterators.
- */
- public CompositeIterator(Collection<? extends Iterator<? extends E>> iterators) {
- this(iterators.iterator());
- }
-
- /**
- * Construct an iterator with the specified collection of iterators.
- */
- public CompositeIterator(Iterator<? extends Iterator<? extends E>> iterators) {
- super();
- this.iterators = iterators;
- }
-
- /**
- * Construct an iterator with the specified object prepended
- * to the specified iterator.
- */
- @SuppressWarnings("unchecked")
- public CompositeIterator(E object, Iterator<? extends E> iterator) {
- this(new SingleElementIterator<E>(object), iterator);
- }
-
- /**
- * Construct an iterator with the specified object appended
- * to the specified iterator.
- */
- @SuppressWarnings("unchecked")
- public CompositeIterator(Iterator<? extends E> iterator, E object) {
- this(iterator, new SingleElementIterator<E>(object));
- }
-
- /**
- * Construct an iterator with the specified iterators.
- */
- public CompositeIterator(Iterator<? extends E>... iterators) {
- this(new ArrayIterator<Iterator<? extends E>>(iterators));
- }
-
-
- // ********** Iterator implementation **********
-
- public boolean hasNext() {
- try {
- this.loadCurrentIterator();
- } catch (NoSuchElementException ex) {
- // this occurs if there are no iterators at all
- return false;
- }
- return this.currentIterator.hasNext();
- }
-
- public E next() {
- this.loadCurrentIterator();
- E result = this.currentIterator.next();
-
- // the statement above will throw a NoSuchElementException
- // if the current iterator is at the end of the line;
- // so if we get here, we can set 'lastIteratorToReturnNext'
- this.lastIteratorToReturnNext = this.currentIterator;
-
- return result;
- }
-
- public void remove() {
- if (this.lastIteratorToReturnNext == null) {
- // CompositeIterator#next() has never been called
- throw new IllegalStateException();
- }
- this.lastIteratorToReturnNext.remove();
- }
-
- /**
- * Load currentIterator with the first iterator that <code>hasNext()</code>
- * or the final iterator if all the elements have already been retrieved.
- */
- private void loadCurrentIterator() {
- if (this.currentIterator == null) {
- this.currentIterator = this.iterators.next();
- }
- while (( ! this.currentIterator.hasNext()) && this.iterators.hasNext()) {
- this.currentIterator = this.iterators.next();
- }
- }
-
-
- // ********** overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.iterators);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java
deleted file mode 100644
index c2037f053d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CompositeListIterator.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.List;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>CompositeListIterator</code> wraps a list
- * of <code>ListIterator</code>s and makes them appear to be a single
- * <code>ListIterator</code>.
- */
-public class CompositeListIterator<E>
- implements ListIterator<E>
-{
- private final ListIterator<? extends ListIterator<E>> iterators;
- private ListIterator<E> nextIterator;
- private int nextIndex;
- /**
- * true if "next" was last returned; false if "previous" was last returned;
- * this determines the effect of remove(Object) on nextIndex
- */
- private boolean nextReturned;
- private ListIterator<E> lastIteratorToReturnElement;
-
-
- /**
- * Construct a list iterator with the specified list of list iterators.
- */
- public CompositeListIterator(List<? extends ListIterator<E>> iterators) {
- this(iterators.listIterator());
- }
-
- /**
- * Construct a list iterator with the specified list of list iterators.
- */
- public CompositeListIterator(ListIterator<? extends ListIterator<E>> iterators) {
- super();
- this.iterators = iterators;
- this.nextIndex = 0;
- this.nextReturned = false;
- }
-
- /**
- * Construct a list iterator with the specified object prepended
- * to the specified iterator.
- */
- @SuppressWarnings("unchecked")
- public CompositeListIterator(E object, ListIterator<E> iterator) {
- this(new SingleElementListIterator<E>(object), iterator);
- }
-
- /**
- * Construct a list iterator with the specified object appended
- * to the specified iterator.
- */
- @SuppressWarnings("unchecked")
- public CompositeListIterator(ListIterator<E> iterator, E object) {
- this(iterator, new SingleElementListIterator<E>(object));
- }
-
- /**
- * Construct a list iterator with the specified list iterators.
- */
- public CompositeListIterator(ListIterator<E>... iterators) {
- this(new ArrayListIterator<ListIterator<E>>(iterators));
- }
-
- public void add(E o) {
- this.checkNextIterator();
- this.nextIterator.add(o);
- this.nextIndex++;
- }
-
- public boolean hasNext() {
- try {
- this.loadNextIterator();
- } catch (NoSuchElementException ex) {
- // this occurs if there are no iterators at all
- return false;
- }
- return this.nextIterator.hasNext();
- }
-
- public boolean hasPrevious() {
- try {
- this.loadPreviousIterator();
- } catch (NoSuchElementException ex) {
- // this occurs if there are no iterators at all
- return false;
- }
- return this.nextIterator.hasPrevious();
- }
-
- public E next() {
- this.loadNextIterator();
- E result = this.nextIterator.next();
-
- // the statement above will throw a NoSuchElementException
- // if the current iterator is at the end of the line;
- // so if we get here, we can set the 'lastIteratorToReturnElement'
- this.lastIteratorToReturnElement = this.nextIterator;
- this.nextIndex++;
- this.nextReturned = true;
-
- return result;
- }
-
- public int nextIndex() {
- return this.nextIndex;
- }
-
- public E previous() {
- this.loadPreviousIterator();
- E result = this.nextIterator.previous();
-
- // the statement above will throw a NoSuchElementException
- // if the current iterator is at the end of the line;
- // so if we get here, we can set the 'lastIteratorToReturnElement'
- this.lastIteratorToReturnElement = this.nextIterator;
- this.nextIndex--;
- this.nextReturned = false;
-
- return result;
- }
-
- public int previousIndex() {
- return this.nextIndex - 1;
- }
-
- public void remove() {
- if (this.lastIteratorToReturnElement == null) {
- throw new IllegalStateException();
- }
- this.lastIteratorToReturnElement.remove();
- if (this.nextReturned) {
- // decrement the index because the "next" element has moved forward in the list
- this.nextIndex--;
- }
- }
-
- public void set(E e) {
- if (this.lastIteratorToReturnElement == null) {
- throw new IllegalStateException();
- }
- this.lastIteratorToReturnElement.set(e);
- }
-
- /**
- * Load 'nextIterator' with the first iterator that <code>hasNext()</code>
- * or the final iterator if all the elements have already been retrieved.
- */
- private void loadNextIterator() {
- this.checkNextIterator();
- while (( ! this.nextIterator.hasNext()) && this.iterators.hasNext()) {
- this.nextIterator = this.iterators.next();
- }
- }
-
- /**
- * Load 'nextIterator' with the first iterator that <code>hasPrevious()</code>
- * or the first iterator if all the elements have already been retrieved.
- */
- private void loadPreviousIterator() {
- this.checkNextIterator();
- while (( ! this.nextIterator.hasPrevious()) && this.iterators.hasPrevious()) {
- this.nextIterator = this.iterators.previous();
- }
- }
-
- /**
- * If 'nextIterator' is null, load it with the first iterator.
- */
- private void checkNextIterator() {
- if (this.nextIterator == null) {
- this.nextIterator = this.iterators.next();
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.iterators);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyEnumeration.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyEnumeration.java
deleted file mode 100644
index 1e7721a892..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyEnumeration.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Enumeration;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>NullEnumeration</code> is just that.
- */
-public final class EmptyEnumeration<E>
- implements Enumeration<E>
-{
-
- // singleton
- @SuppressWarnings("unchecked")
- private static final EmptyEnumeration INSTANCE = new EmptyEnumeration();
-
- /**
- * Return the singleton.
- */
- @SuppressWarnings("unchecked")
- public static <T> Enumeration<T> instance() {
- return INSTANCE;
- }
-
- /**
- * Ensure single instance.
- */
- private EmptyEnumeration() {
- super();
- }
-
- public boolean hasMoreElements() {
- return false;
- }
-
- public E nextElement() {
- throw new NoSuchElementException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java
deleted file mode 100644
index aacac33339..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyIterator.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * An <code>EmptyIterator</code> is just that.
- */
-public final class EmptyIterator<E>
- implements Iterator<E>
-{
-
- // singleton
- @SuppressWarnings("unchecked")
- private static final EmptyIterator INSTANCE = new EmptyIterator();
-
- /**
- * Return the singleton.
- */
- @SuppressWarnings("unchecked")
- public static <T> Iterator<T> instance() {
- return INSTANCE;
- }
-
- /**
- * Ensure single instance.
- */
- private EmptyIterator() {
- super();
- }
-
- public boolean hasNext() {
- return false;
- }
-
- public E next() {
- throw new NoSuchElementException();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java
deleted file mode 100644
index f3ab4a464f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EmptyListIterator.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * An <code>EmptyListIterator</code> is just that.
- */
-public final class EmptyListIterator<E>
- implements ListIterator<E>
-{
-
- // singleton
- @SuppressWarnings("unchecked")
- private static final EmptyListIterator INSTANCE = new EmptyListIterator();
-
- /**
- * Return the singleton.
- */
- @SuppressWarnings("unchecked")
- public static <T> ListIterator<T> instance() {
- return INSTANCE;
- }
-
- /**
- * Ensure single instance.
- */
- private EmptyListIterator() {
- super();
- }
-
- public void add(E e) {
- throw new UnsupportedOperationException();
- }
-
- public boolean hasNext() {
- return false;
- }
-
- public boolean hasPrevious() {
- return false;
- }
-
- public E next() {
- throw new NoSuchElementException();
- }
-
- public int nextIndex() {
- return 0;
- }
-
- public E previous() {
- throw new NoSuchElementException();
- }
-
- public int previousIndex() {
- return -1;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public void set(E e) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EnumerationIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EnumerationIterator.java
deleted file mode 100644
index a75710c4ef..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/EnumerationIterator.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Enumeration;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * An <code>EnumerationIterator</code> wraps an
- * <code>Enumeration</code> so that it can be treated like an
- * <code>Iterator</code>.
- */
-public class EnumerationIterator<E>
- implements Iterator<E>
-{
- private final Enumeration<? extends E> enumeration;
-
- /**
- * Construct an iterator that wraps the specified enumeration.
- */
- public EnumerationIterator(Enumeration<? extends E> enumeration) {
- this.enumeration = enumeration;
- }
-
- public boolean hasNext() {
- return this.enumeration.hasMoreElements();
- }
-
- public E next() {
- return this.enumeration.nextElement();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.enumeration);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java
deleted file mode 100644
index fa22c65476..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/FilteringIterator.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.Filter;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>FilteringIterator</code> wraps another <code>Iterator</code>
- * and uses a <code>Filter</code> to determine which elements in the
- * nested iterator are to be returned by calls to <code>next()</code>.
- * <p>
- * As an alternative to building a <code>Filter</code>, a subclass
- * of <code>FilteringIterator</code> can override the
- * <code>accept(Object)</code> method.
- * <p>
- * One, possibly undesirable, side-effect of using this iterator is that
- * the nested iterator's <code>next()</code> method will be invoked
- * <em>before</em> the filtered iterator's <code>next()</code>
- * method is invoked. This is because the "next" element must be
- * checked for whether it is to be accepted before the filtered iterator
- * can determine whether it has a "next" element (i.e. that the
- * <code>hasNext()</code> method should return <code>true</code>).
- * This also prevents a filtered iterator from supporting the optional
- * <code>remove()</code> method.
- */
-public class FilteringIterator<E1, E2>
- implements Iterator<E2>
-{
- private final Iterator<? extends E1> nestedIterator;
- private final Filter<E1> filter;
- private E2 next;
- private boolean done;
-
-
- /**
- * Construct an iterator with the specified nested
- * iterator and a disabled filter.
- * Use this constructor if you want to override the
- * <code>accept(Object)</code> method instead of building
- * a <code>Filter</code>.
- */
- public FilteringIterator(Iterator<? extends E1> nestedIterator) {
- this(nestedIterator, Filter.Disabled.<E1>instance());
- }
-
- /**
- * Construct an iterator with the specified nested
- * iterator and filter.
- */
- public FilteringIterator(Iterator<? extends E1> nestedIterator, Filter<E1> filter) {
- super();
- this.nestedIterator = nestedIterator;
- this.filter = filter;
- this.loadNext();
- }
-
- public boolean hasNext() {
- return ! this.done;
- }
-
- public E2 next() {
- if (this.done) {
- throw new NoSuchElementException();
- }
- E2 result = this.next;
- this.loadNext();
- return result;
- }
-
- /**
- * Because we need to pre-load the next element
- * to be returned, we cannot support the <code>remove()</code>
- * method.
- */
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Load next with the next valid entry from the nested
- * iterator. If there are none, next is set to <code>END</code>.
- */
- private void loadNext() {
- this.done = true;
- while (this.nestedIterator.hasNext() && (this.done)) {
- E1 temp = this.nestedIterator.next();
- if (this.accept(temp)) {
- // assume that if the object was accepted it is of type E
- this.next = this.cast(temp);
- this.done = false;
- } else {
- this.next = null;
- this.done = true;
- }
- }
- }
-
- /**
- * We have to assume the filter will only "accept" objects that can
- * be cast to E2.
- */
- @SuppressWarnings("unchecked")
- private E2 cast(E1 o) {
- return (E2) o;
- }
-
- /**
- * Return whether the <code>FilteringIterator</code>
- * should return the specified next element from a call to the
- * <code>next()</code> method.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Filter</code>.
- */
- protected boolean accept(E1 o) {
- return this.filter.accept(o);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nestedIterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GenericIteratorWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GenericIteratorWrapper.java
deleted file mode 100644
index 01e5e0a93b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GenericIteratorWrapper.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * Wrap an iterator on elements of any sub-type of E, converting it into an
- * iterator on elements of type E. This shouldn't be a problem since there
- * is no way to add elements to the iterator.
- */
-public class GenericIteratorWrapper<E>
- implements Iterator<E>
-{
- private final Iterator<? extends E> iterator;
-
- public GenericIteratorWrapper(Iterator<? extends E> iterator) {
- super();
- this.iterator = iterator;
- }
-
- public boolean hasNext() {
- return this.iterator.hasNext();
- }
-
- public E next() {
- return this.iterator.next();
- }
-
- public void remove() {
- this.iterator.remove();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.iterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java
deleted file mode 100644
index c199e6ec4c..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>GraphIterator</code> is similar to a <code>TreeIterator</code>
- * except that it cannot be assumed that all nodes assume a strict tree
- * structure. For instance, in a tree, a node cannot be a descendent of
- * itself, but a graph may have a cyclical structure.
- *
- * A <code>GraphIterator</code> simplifies the traversal of a
- * graph of objects, where the objects' protocol(s) provides
- * a method for getting the next collection of nodes in the graph,
- * (or *neighbors*), but does not provide a method for getting *all*
- * of the nodes in the graph.
- * (e.g. a neighbor can return his neighbors, and those neighbors
- * can return their neighbors, which might also include the original
- * neighbor, but you only want to visit the original neighbor once.)
- * <p>
- * If a neighbor has already been visited (determined by using
- * <code>equals(Object)</code>), that neighbor is not visited again,
- * nor are the neighbors of that object.
- * <p>
- * It is up to the user of this class to ensure a *complete* graph.
- * <p>
- * To use, supply:<ul>
- * <li> either the initial node of the graph or an Iterator over an
- * initial collection of graph nodes
- * <li> a <code>MisterRogers</code> that tells who the neighbors are
- * of each node
- * (alternatively, subclass <code>GraphIterator</code>
- * and override the <code>neighbors(Object)</code> method)
- * </ul>
- * <p>
- * <code>remove()</code> is not supported. This method, if
- * desired, must be implemented by the user of this class.
- */
-public class GraphIterator<E>
- implements Iterator<E>
-{
- private final Collection<Iterator<? extends E>> iterators;
- private final Set<E> visitedNeighbors;
- private final MisterRogers<E> misterRogers;
-
- private Iterator<? extends E> currentIterator;
-
- private E nextNeighbor;
- private boolean done;
-
-
- /**
- * Construct an iterator with the specified collection of roots
- * and a disabled mister rogers.
- * Use this constructor if you want to override the
- * <code>children(Object)</code> method instead of building
- * a <code>MisterRogers</code>.
- */
- public GraphIterator(E... roots) {
- this(new ArrayIterator<E>(roots));
- }
-
- /**
- * Construct an iterator with the specified collection of roots
- * and a disabled mister rogers.
- * Use this constructor if you want to override the
- * <code>children(Object)</code> method instead of building
- * a <code>MisterRogers</code>.
- */
- public GraphIterator(Iterator<? extends E> roots) {
- this(roots, MisterRogers.Disabled.<E>instance());
- }
-
- /**
- * Construct an iterator with the specified root
- * and a disabled mister rogers.
- * Use this constructor if you want to override the
- * <code>children(Object)</code> method instead of building
- * a <code>MisterRogers</code>.
- */
- public GraphIterator(E root) {
- this(root, MisterRogers.Disabled.<E>instance());
- }
-
- /**
- * Construct an iterator with the specified root
- * and mister rogers.
- */
- public GraphIterator(E root, MisterRogers<E> misterRogers) {
- this(new SingleElementIterator<E>(root), misterRogers);
- }
-
- /**
- * Construct an iterator with the specified roots
- * and mister rogers.
- */
- public GraphIterator(Iterator<? extends E> roots, MisterRogers<E> misterRogers) {
- super();
- this.currentIterator = roots;
- // use a LinkedList since we will be pulling off the front and adding to the end
- this.iterators = new LinkedList<Iterator<? extends E>>();
- this.misterRogers = misterRogers;
- this.visitedNeighbors = new HashSet<E>();
- this.loadNextNeighbor();
- }
-
- /**
- * Load next neighbor with the next entry from the current iterator.
- * If the current iterator has none, load the next iterator.
- * If there are no more, the 'done' flag is set.
- */
- private void loadNextNeighbor() {
- if (this.currentIterator == EmptyIterator.instance()) {
- this.done = true;
- }
- else if (this.currentIterator.hasNext()) {
- E nextPossibleNeighbor = this.currentIterator.next();
- if (this.visitedNeighbors.contains(nextPossibleNeighbor)) {
- this.loadNextNeighbor(); // recurse
- } else {
- this.nextNeighbor = nextPossibleNeighbor;
- this.visitedNeighbors.add(nextPossibleNeighbor);
- this.iterators.add(this.neighbors(nextPossibleNeighbor));
- }
- }
- else {
- for (Iterator<? extends Iterator<? extends E>> stream = this.iterators.iterator(); ! this.currentIterator.hasNext() && stream.hasNext(); ) {
- this.currentIterator = stream.next();
- stream.remove();
- }
- if ( ! this.currentIterator.hasNext()) {
- this.currentIterator = EmptyIterator.instance();
- }
- this.loadNextNeighbor(); // recurse
- }
- }
-
- public boolean hasNext() {
- return ! this.done;
- }
-
- public E next() {
- if (this.done) {
- throw new NoSuchElementException();
- }
- E next = this.nextNeighbor;
- this.loadNextNeighbor();
- return next;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Return the immediate neighbors of the specified object.
- */
- protected Iterator<? extends E> neighbors(E next) {
- return this.misterRogers.neighbors(next);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.currentIterator);
- }
-
-
- //********** inner classes **********
-
- /**
- * Used by <code>GraphIterator</code> to retrieve
- * the immediate neighbors of a node in the graph.
- * "These are the people in your neighborhood..."
- */
- public interface MisterRogers<T> {
-
- /**
- * Return the immediate neighbors of the specified object.
- */
- Iterator<? extends T> neighbors(T next);
-
-
- final class Null<S> implements MisterRogers<S> {
- @SuppressWarnings("unchecked")
- public static final MisterRogers INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R> MisterRogers<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // return no neighbors
- public Iterator<S> neighbors(S next) {
- return EmptyIterator.instance();
- }
- @Override
- public String toString() {
- return "GraphIterator.MisterRogers.Null";
- }
- }
-
- /** The mister rogers used when the #neighbors(Object) method is overridden. */
- final class Disabled<S> implements MisterRogers<S> {
- @SuppressWarnings("unchecked")
- public static final MisterRogers INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> MisterRogers<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public Iterator<S> neighbors(S next) {
- throw new UnsupportedOperationException(); // GraphIterator.neighbors(Object) was not implemented
- }
- @Override
- public String toString() {
- return "GraphIterator.MisterRogers.Disabled";
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/IteratorEnumeration.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/IteratorEnumeration.java
deleted file mode 100644
index 55a4f08b70..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/IteratorEnumeration.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Enumeration;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * An <code>IteratorEnumeration</code> wraps an
- * <code>Iterator</code> so that it can be treated like an
- * <code>Enumeration</code>.
- */
-public class IteratorEnumeration<E>
- implements Enumeration<E>
-{
- private final Iterator<? extends E> iterator;
-
- /**
- * Construct an enumeration that wraps the specified iterator.
- */
- public IteratorEnumeration(Iterator<? extends E> iterator) {
- super();
- this.iterator = iterator;
- }
-
- public boolean hasMoreElements() {
- return this.iterator.hasNext();
- }
-
- public E nextElement() {
- return this.iterator.next();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.iterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/PeekableIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/PeekableIterator.java
deleted file mode 100644
index 316aedcf63..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/PeekableIterator.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>PeekableIterator</code> wraps another <code>Iterator</code>
- * and allows a <code>peek()</code> at the next element to be
- * returned by <code>next()</code>.
- * <p>
- * One, possibly undesirable, side-effect of using this iterator is that
- * the nested iterator's <code>next()</code> method will be invoked
- * <em>before</em> the peekable iterator's <code>next()</code>
- * method is invoked. This is because the "next" element must be
- * pre-loaded for the <code>peek()</code> method.
- * This also prevents a peekable iterator from supporting the optional
- * <code>remove()</code> method.
- */
-
-public class PeekableIterator<E>
- implements Iterator<E>
-{
- private final Iterator<? extends E> nestedIterator;
- private E next;
- private boolean done;
-
-
- /**
- * Construct a peekable iterator that wraps the specified nested
- * iterator.
- */
- public PeekableIterator(Iterator<? extends E> nestedIterator) {
- super();
- this.nestedIterator = nestedIterator;
- this.done = false;
- this.loadNext();
- }
-
- public boolean hasNext() {
- return ! this.done;
- }
-
- public E next() {
- if (this.done) {
- throw new NoSuchElementException();
- }
- E result = this.next;
- this.loadNext();
- return result;
- }
-
- /**
- * Return the element that will be returned by the next call to the
- * <code>next()</code> method, without advancing past it.
- */
- public E peek() {
- if (this.done) {
- throw new NoSuchElementException();
- }
- return this.next;
- }
-
- /**
- * Because we need to pre-load the next element
- * to be returned, we cannot support the <code>remove()</code>
- * method.
- */
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Load next with the next entry from the nested
- * iterator. If there are none, next is set to <code>END</code>.
- */
- private void loadNext() {
- if (this.nestedIterator.hasNext()) {
- this.next = this.nestedIterator.next();
- } else {
- this.next = null;
- this.done = true;
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nestedIterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java
deleted file mode 100644
index 92d896c65c..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyCompositeListIterator.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.List;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>ReadOnlyCompositeListIterator</code> wraps a list
- * of <code>ListIterator</code>s and makes them appear to be a single
- * read-only <code>ListIterator</code>. A read-only composite list
- * iterator is more flexible than a normal composite when it comes to the element types of
- * the nested iterators.
- */
-public class ReadOnlyCompositeListIterator<E>
- implements ListIterator<E>
-{
- private final ListIterator<? extends ListIterator<? extends E>> iterators;
- private ListIterator<? extends E> nextIterator;
- private int nextIndex;
-
-
- /**
- * Construct a read-only list iterator with the specified list of
- * list iterators.
- */
- public ReadOnlyCompositeListIterator(List<? extends ListIterator<? extends E>> iterators) {
- this(iterators.listIterator());
- }
-
- /**
- * Construct a read-only list iterator with the specified list of
- * list iterators.
- */
- public ReadOnlyCompositeListIterator(ListIterator<? extends ListIterator<? extends E>> iterators) {
- super();
- this.iterators = iterators;
- this.nextIndex = 0;
- }
-
- /**
- * Construct a read-only list iterator with the specified object prepended
- * to the specified iterator.
- */
- @SuppressWarnings("unchecked")
- public ReadOnlyCompositeListIterator(E object, ListIterator<? extends E> iterator) {
- this(new SingleElementListIterator<E>(object), iterator);
- }
-
- /**
- * Construct a read-only list iterator with the specified object appended
- * to the specified iterator.
- */
- @SuppressWarnings("unchecked")
- public ReadOnlyCompositeListIterator(ListIterator<? extends E> iterator, E object) {
- this(iterator, new SingleElementListIterator<E>(object));
- }
-
- /**
- * Construct a read-only list iterator with the specified list iterators.
- */
- public ReadOnlyCompositeListIterator(ListIterator<? extends E>... iterators) {
- this(new ArrayListIterator<ListIterator<? extends E>>(iterators));
- }
-
- public boolean hasNext() {
- try {
- this.loadNextIterator();
- } catch (NoSuchElementException ex) {
- // this occurs if there are no iterators at all
- return false;
- }
- return this.nextIterator.hasNext();
- }
-
- public boolean hasPrevious() {
- try {
- this.loadPreviousIterator();
- } catch (NoSuchElementException ex) {
- // this occurs if there are no iterators at all
- return false;
- }
- return this.nextIterator.hasPrevious();
- }
-
- public E next() {
- this.loadNextIterator();
- E result = this.nextIterator.next();
-
- // the statement above will throw a NoSuchElementException
- // if the current iterator is at the end of the line;
- // so if we get here, we can increment 'nextIndex'
- this.nextIndex++;
-
- return result;
- }
-
- public int nextIndex() {
- return this.nextIndex;
- }
-
- public E previous() {
- this.loadPreviousIterator();
- E result = this.nextIterator.previous();
-
- // the statement above will throw a NoSuchElementException
- // if the current iterator is at the end of the line;
- // so if we get here, we can decrement 'nextIndex'
- this.nextIndex--;
-
- return result;
- }
-
- public int previousIndex() {
- return this.nextIndex - 1;
- }
-
- public void add(E o) {
- // the list iterator is read-only
- throw new UnsupportedOperationException();
- }
-
- public void remove() {
- // the list iterator is read-only
- throw new UnsupportedOperationException();
- }
-
- public void set(E e) {
- // the list iterator is read-only
- throw new UnsupportedOperationException();
- }
-
- /**
- * Load nextIterator with the first iterator that <code>hasNext()</code>
- * or the final iterator if all the elements have already been retrieved.
- */
- private void loadNextIterator() {
- this.checkNextIterator();
- while (( ! this.nextIterator.hasNext()) && this.iterators.hasNext()) {
- this.nextIterator = this.iterators.next();
- }
- }
-
- /**
- * Load nextIterator with the first iterator that <code>hasPrevious()</code>
- * or the first iterator if all the elements have already been retrieved.
- */
- private void loadPreviousIterator() {
- this.checkNextIterator();
- while (( ! this.nextIterator.hasPrevious()) && this.iterators.hasPrevious()) {
- this.nextIterator = this.iterators.previous();
- }
- }
-
- /**
- * If 'nextIterator' is null, load it with the first iterator.
- */
- private void checkNextIterator() {
- if (this.nextIterator == null) {
- this.nextIterator = this.iterators.next();
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.iterators);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyIterator.java
deleted file mode 100644
index df0a51333d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyIterator.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>ReadOnlyIterator</code> wraps another <code>Iterator</code>
- * and removes support for #remove().
- */
-public class ReadOnlyIterator<E>
- implements Iterator<E>
-{
- private final Iterator<? extends E> nestedIterator;
-
- /**
- * Construct an iterator on the specified collection that
- * disallows removes.
- */
- public ReadOnlyIterator(Collection<? extends E> c) {
- this(c.iterator());
- }
-
- /**
- * Construct an iterator with the specified nested iterator
- * and disallow removes.
- */
- public ReadOnlyIterator(Iterator<? extends E> nestedIterator) {
- super();
- this.nestedIterator = nestedIterator;
- }
-
- public boolean hasNext() {
- // delegate to the nested iterator
- return this.nestedIterator.hasNext();
- }
-
- public E next() {
- // delegate to the nested iterator
- return this.nestedIterator.next();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nestedIterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyListIterator.java
deleted file mode 100644
index c3b2591f44..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ReadOnlyListIterator.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>ReadOnlyListIterator</code> wraps another
- * <code>ListIterator</code> and removes support for:
- * #remove()
- * #set(Object)
- * #add(Object)
- */
-public class ReadOnlyListIterator<E>
- implements ListIterator<E>
-{
- private final ListIterator<? extends E> nestedListIterator;
-
-
- /**
- * Construct an iterator on the specified list that
- * disallows removes, sets, and adds.
- */
- public ReadOnlyListIterator(List<? extends E> list) {
- this(list.listIterator());
- }
-
- /**
- * Construct an iterator on the specified list iterator that
- * disallows removes, sets, and adds.
- */
- public ReadOnlyListIterator(ListIterator<? extends E> nestedListIterator) {
- super();
- this.nestedListIterator = nestedListIterator;
- }
-
- public boolean hasNext() {
- // delegate to the nested iterator
- return this.nestedListIterator.hasNext();
- }
-
- public E next() {
- // delegate to the nested iterator
- return this.nestedListIterator.next();
- }
-
- public boolean hasPrevious() {
- // delegate to the nested iterator
- return this.nestedListIterator.hasPrevious();
- }
-
- public E previous() {
- // delegate to the nested iterator
- return this.nestedListIterator.previous();
- }
-
- public int nextIndex() {
- // delegate to the nested iterator
- return this.nestedListIterator.nextIndex();
- }
-
- public int previousIndex() {
- // delegate to the nested iterator
- return this.nestedListIterator.previousIndex();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public void set(E o) {
- throw new UnsupportedOperationException();
- }
-
- public void add(E o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nestedListIterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ResultSetIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ResultSetIterator.java
deleted file mode 100644
index a8da8442ab..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ResultSetIterator.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>ResultSetIterator</code> wraps a <code>ResultSet</code>
- * and transforms its rows for client consumption. Subclasses can override
- * <code>#buildNext(ResultSet)</code> to build the expected object from
- * the current row of the result set.
- * <p>
- * To use, supply:<ul>
- * <li> a <code>ResultSet</code>
- * <li> an <code>Adapter</code> that converts a row in the <code>ResultSet</code>
- * into the desired object
- * (alternatively, subclass <code>ResultSetIterator</code>
- * and override the <code>buildNext(ResultSet)</code> method)
- * </ul>
- * <p>
- */
-public class ResultSetIterator<E>
- implements Iterator<E>
-{
- private final ResultSet resultSet;
- private final Adapter<E> adapter;
- private E next;
- private boolean done;
-
-
- /**
- * Construct an iterator on the specified result set that returns
- * the objects produced by the specified adapter.
- */
- public ResultSetIterator(ResultSet resultSet, Adapter<E> adapter) {
- super();
- this.resultSet = resultSet;
- this.adapter = adapter;
- this.done = false;
- this.next = this.buildNext();
- }
-
- /**
- * Construct an iterator on the specified result set that returns
- * the first object in each row of the result set.
- */
- public ResultSetIterator(ResultSet resultSet) {
- this(resultSet, Adapter.Default.<E>instance());
- }
-
- /**
- * Build the next object for the iterator to return.
- * Close the result set when we reach the end.
- */
- private E buildNext() {
- try {
- if (this.resultSet.next()) {
- return this.buildNext(this.resultSet);
- }
- this.resultSet.close();
- this.done = true;
- return null;
- } catch (SQLException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- /**
- * By default, return the first object in the current row
- * of the result set. Any <code>SQLException</code>s will
- * be caught and wrapped in a <code>RuntimeException</code>.
- */
- protected E buildNext(ResultSet rs) throws SQLException {
- return this.adapter.buildNext(rs);
- }
-
- public boolean hasNext() {
- return ! this.done;
- }
-
- public E next() {
- if (this.done) {
- throw new NoSuchElementException();
- }
- E temp = this.next;
- this.next = this.buildNext();
- return temp;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.resultSet);
- }
-
-
- // ********** interface **********
-
- /**
- * Used by <code>ResultSetIterator</code> to convert a
- * <code>ResultSet</code>'s current row into the next object
- * to be returned by the <code>Iterator</code>.
- */
- public interface Adapter<T> {
-
- /**
- * Return an object corresponding to the result set's
- * "current" row. Any <code>SQLException</code>s will
- * be caught and wrapped in a <code>RuntimeException</code>.
- * @see java.sql.ResultSet
- */
- T buildNext(ResultSet rs) throws SQLException;
-
-
- final class Default<S> implements Adapter<S> {
- @SuppressWarnings("unchecked")
- public static final Adapter INSTANCE = new Default();
- @SuppressWarnings("unchecked")
- public static <R> Adapter<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Default() {
- super();
- }
- // return the first object in the current row of the result set
- @SuppressWarnings("unchecked")
- public S buildNext(ResultSet rs) throws SQLException {
- // result set columns are indexed starting with 1
- return (S) rs.getObject(1);
- }
- @Override
- public String toString() {
- return "ResultSetIterator.Adapter.Default";
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementIterator.java
deleted file mode 100644
index 75fd9d80fd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementIterator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>SingleElementIterator</code> holds a single element
- * and returns it with the first call to <code>next()</code>, at
- * which point it will return <code>false</code> to any subsequent
- * call to <code>hasNext()</code>.
- * <p>
- * A <code>SingleElementIterator</code> is equivalent to the
- * <code>Iterator</code> returned by:
- * <code>java.util.Collections.singleton(element).iterator()</code>
- */
-public class SingleElementIterator<E>
- implements Iterator<E>
-{
- private final E element;
- private boolean done;
-
-
- /**
- * Construct an iterator that returns only the specified element.
- */
- public SingleElementIterator(E element) {
- super();
- this.element = element;
- this.done = false;
- }
-
- public boolean hasNext() {
- return ! this.done;
- }
-
- public E next() {
- if (this.done) {
- throw new NoSuchElementException();
- }
- this.done = true;
- return this.element;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.element);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementListIterator.java
deleted file mode 100644
index 799cb72aef..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SingleElementListIterator.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>SingleElementListIterator</code> holds a single element
- * and returns it with the first call to <code>next()</code>, at
- * which point it will return <code>false</code> to any subsequent
- * call to <code>hasNext()</code>. Likewise, it will return <code>false</code>
- * to a call to <code>hasPrevious()</code> until a call to <code>next()</code>,
- * at which point a call to <code>previous()</code> will return the
- * single element.
- * <p>
- * A <code>SingleElementListIterator</code> is equivalent to the
- * <code>Iterator</code> returned by:
- * <code>java.util.Collections.singletonList(element).listIterator()</code>
- */
-public class SingleElementListIterator<E>
- implements ListIterator<E>
-{
- private final E element;
- private boolean hasNext;
-
-
- /**
- * Construct a list iterator that returns only the specified element.
- */
- public SingleElementListIterator(E element) {
- super();
- this.element = element;
- this.hasNext = true;
- }
-
- public boolean hasNext() {
- return this.hasNext;
- }
-
- public E next() {
- if (this.hasNext) {
- this.hasNext = false;
- return this.element;
- }
- throw new NoSuchElementException();
- }
-
- public int nextIndex() {
- return this.hasNext ? 0 : 1;
- }
-
- public boolean hasPrevious() {
- return ! this.hasNext;
- }
-
- public E previous() {
- if (this.hasNext) {
- throw new NoSuchElementException();
- }
- this.hasNext = true;
- return this.element;
- }
-
- public int previousIndex() {
- return this.hasNext ? -1 : 0;
- }
-
- public void add(E e) {
- throw new UnsupportedOperationException();
- }
-
- public void set(E e) {
- throw new UnsupportedOperationException();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.element);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationIterator.java
deleted file mode 100644
index b970d28841..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationIterator.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.Transformer;
-
-
-/**
- * A <code>TransformationIterator</code> wraps another <code>Iterator</code>
- * and transforms its results for client consumption. To use, supply a
- * <code>Transformer</code> or subclass <code>TransformationIterator</code>
- * and override the <code>transform(Object)</code> method.
- * Objects of type E1 are transformed into objects of type E2;
- * i.e. the iterator returns objects of type E2.
- */
-public class TransformationIterator<E1, E2>
- implements Iterator<E2>
-{
- private final Iterator<? extends E1> nestedIterator;
- private final Transformer<E1, ? extends E2> transformer;
-
-
- /**
- * Construct an iterator with the specified nested iterator
- * and a disabled transformer.
- * Use this constructor if you want to override the
- * <code>transform(Object)</code> method instead of building
- * a <code>Transformer</code>.
- */
- public TransformationIterator(Iterator<? extends E1> nestedIterator) {
- this(nestedIterator, Transformer.Disabled.<E1, E2>instance());
- }
-
- /**
- * Construct an iterator with the specified nested iterator
- * and transformer.
- */
- public TransformationIterator(Iterator<? extends E1> nestedIterator, Transformer<E1, ? extends E2> transformer) {
- super();
- this.nestedIterator = nestedIterator;
- this.transformer = transformer;
- }
-
- public boolean hasNext() {
- // delegate to the nested iterator
- return this.nestedIterator.hasNext();
- }
-
- public E2 next() {
- // transform the object returned by the nested iterator before returning it
- return this.transform(this.nestedIterator.next());
- }
-
- public void remove() {
- // delegate to the nested iterator
- this.nestedIterator.remove();
- }
-
- /**
- * Transform the specified object and return the result.
- */
- protected E2 transform(E1 next) {
- return this.transformer.transform(next);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nestedIterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationListIterator.java
deleted file mode 100644
index 087fc11046..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TransformationListIterator.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.Transformer;
-
-/**
- * A <code>TransformationListIterator</code> wraps another <code>ListIterator</code>
- * and transforms its results for client consumption. To use, supply a
- * <code>Transformer</code> or subclass <code>TransformationIterator</code>
- * and override the <code>transform(Object)</code> method.
- *
- * The methods <code>set(Object)</code> and <code>add(Object)</code>
- * are left unsupported in this class.
- */
-public class TransformationListIterator<E1, E2>
- implements ListIterator<E2>
-{
- private final ListIterator<? extends E1> nestedIterator;
- private final Transformer<E1, ? extends E2> transformer;
-
-
- /**
- * Construct an iterator with the specified nested iterator
- * and a disabled transformer.
- * Use this constructor if you want to override the
- * <code>transform(Object)</code> method instead of building
- * a <code>Transformer</code>.
- */
- public TransformationListIterator(ListIterator<? extends E1> nestedIterator) {
- this(nestedIterator, Transformer.Disabled.<E1, E2>instance());
- }
-
- /**
- * Construct an iterator with the specified nested iterator
- * and transformer.
- */
- public TransformationListIterator(ListIterator<? extends E1> nestedIterator, Transformer<E1, ? extends E2> transformer) {
- super();
- this.nestedIterator = nestedIterator;
- this.transformer = transformer;
- }
-
- public boolean hasNext() {
- // delegate to the nested iterator
- return this.nestedIterator.hasNext();
- }
-
- public E2 next() {
- // transform the object returned by the nested iterator before returning it
- return this.transform(this.nestedIterator.next());
- }
-
- public int nextIndex() {
- // delegate to the nested iterator
- return this.nestedIterator.nextIndex();
- }
-
- public boolean hasPrevious() {
- // delegate to the nested iterator
- return this.nestedIterator.hasPrevious();
- }
-
- public E2 previous() {
- // transform the object returned by the nested iterator before returning it
- return this.transform(this.nestedIterator.previous());
- }
-
- public int previousIndex() {
- // delegate to the nested iterator
- return this.nestedIterator.previousIndex();
- }
-
- public void add(E2 o) {
- throw new UnsupportedOperationException();
- }
-
- public void set(E2 o) {
- throw new UnsupportedOperationException();
- }
-
- public void remove() {
- // delegate to the nested iterator
- this.nestedIterator.remove();
- }
-
- /**
- * Transform the specified object and return the result.
- */
- protected E2 transform(E1 next) {
- return this.transformer.transform(next);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.nestedIterator);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TreeIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TreeIterator.java
deleted file mode 100644
index 47074d7c7d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/TreeIterator.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.iterators;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * A <code>TreeIterator</code> simplifies the traversal of a
- * tree of objects, where the objects' protocol(s) provides
- * a method for getting the immediate children of the given
- * node but does not provide a method for getting all the
- * descendants (children, grandchildren, etc.) of the given node.
- * <p>
- * To use, supply:<ul>
- * <li> either the root element of the tree or, if the tree has
- * multiple roots, an <code>Iterator</code> over the set of roots
- * <li> a <code>Midwife</code> that delivers the children
- * of each child
- * (alternatively, subclass <code>TreeIterator</code>
- * and override the <code>children(Object)</code> method)
- * </ul>
- * <p>
- */
-public class TreeIterator<E>
- implements Iterator<E>
-{
- private final LinkedList<Iterator<? extends E>> iterators;
- private final Midwife<E> midwife;
- private Iterator<? extends E> currentIterator;
-
-
- /**
- * Construct an iterator with the specified collection of roots
- * and a disabled midwife.
- * Use this constructor if you want to override the
- * <code>children(Object)</code> method instead of building
- * a <code>Midwife</code>.
- */
- public TreeIterator(Iterator<? extends E> roots) {
- this(roots, Midwife.Disabled.<E>instance());
- }
-
- /**
- * Construct an iterator with the specified root
- * and a disabled midwife.
- * Use this constructor if you want to override the
- * <code>children(Object)</code> method instead of building
- * a <code>Midwife</code>.
- */
- public TreeIterator(E root) {
- this(root, Midwife.Disabled.<E>instance());
- }
-
- /**
- * Construct an iterator with the specified root
- * and midwife.
- */
- public TreeIterator(E root, Midwife<E> midwife) {
- this(new SingleElementIterator<E>(root), midwife);
- }
-
- /**
- * Construct an iterator with the specified roots
- * and midwife.
- */
- public TreeIterator(Iterator<? extends E> roots, Midwife<E> midwife) {
- super();
- this.currentIterator = roots;
- // use a LinkedList since we will be pulling off the front and adding to the end
- this.iterators = new LinkedList<Iterator<? extends E>>();
- this.midwife = midwife;
- }
-
- public boolean hasNext() {
- if (this.currentIterator.hasNext()) {
- return true;
- }
- for (Iterator<? extends E> iterator : this.iterators) {
- if (iterator.hasNext()) {
- return true;
- }
- }
- return false;
- }
-
- public E next() {
- if (this.currentIterator.hasNext()) {
- return this.nextInternal();
- }
- for (Iterator<Iterator<? extends E>> stream = this.iterators.iterator(); stream.hasNext(); ) {
- this.currentIterator = stream.next();
- if (this.currentIterator.hasNext()) {
- break;
- }
- stream.remove();
- }
- return this.nextInternal();
- }
-
- /**
- * Fetch the children of the next node before returning it.
- */
- private E nextInternal() {
- E next = this.currentIterator.next();
- this.iterators.add(this.children(next));
- return next;
- }
-
- public void remove() {
- this.currentIterator.remove();
- }
-
- /**
- * Return the immediate children of the specified object.
- */
- protected Iterator<? extends E> children(E next) {
- return this.midwife.children(next);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.currentIterator);
- }
-
-
- //********** inner classes **********
-
- /**
- * Used by <code>TreeIterator</code> to retrieve
- * the immediate children of a node in the tree.
- */
- public interface Midwife<T> {
-
- /**
- * Return the immediate children of the specified object.
- */
- Iterator<? extends T> children(T o);
-
-
- final class Null<S> implements Midwife<S> {
- @SuppressWarnings("unchecked")
- public static final Midwife INSTANCE = new Null();
- @SuppressWarnings("unchecked")
- public static <R> Midwife<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- // return no neighbors
- public Iterator<S> children(S next) {
- return EmptyIterator.instance();
- }
- @Override
- public String toString() {
- return "TreeIterator.Midwife.Null"; //$NON-NLS-1$
- }
- }
-
- /** The midwife used when the #children(Object) method is overridden. */
- final class Disabled<S> implements Midwife<S> {
- @SuppressWarnings("unchecked")
- public static final Midwife INSTANCE = new Disabled();
- @SuppressWarnings("unchecked")
- public static <R> Midwife<R> instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Disabled() {
- super();
- }
- // throw an exception
- public Iterator<S> children(S next) {
- throw new UnsupportedOperationException(); // TreeIterator.children(Object) was not implemented
- }
- @Override
- public String toString() {
- return "TreeIterator.Midwife.Disabled"; //$NON-NLS-1$
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java
deleted file mode 100644
index e81db41721..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/AbstractModel.java
+++ /dev/null
@@ -1,996 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.HashBag;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-
-/**
- * Convenience implementation of Model protocol.
- */
-public abstract class AbstractModel implements Model, Serializable {
- /**
- * Delegate state/property/collection/list/tree change support to this
- * helper object. The change support object is "lazy-initialized".
- */
- private ChangeSupport changeSupport;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Default constructor.
- * This will call #initialize() on the newly-created instance.
- */
- protected AbstractModel() {
- super();
- }
-
- /**
- * This accessor will build the change support when required.
- */
- protected synchronized ChangeSupport getChangeSupport() {
- if (this.changeSupport == null) {
- this.changeSupport = this.buildChangeSupport();
- }
- return this.changeSupport;
- }
-
- /**
- * Allow subclasses to tweak the change support used.
- */
- protected ChangeSupport buildChangeSupport() {
- return new ChangeSupport(this);
- }
-
-
- // ********** state change support **********
-
- public synchronized void addStateChangeListener(StateChangeListener listener) {
- this.getChangeSupport().addStateChangeListener(listener);
- }
-
- public synchronized void removeStateChangeListener(StateChangeListener listener) {
- this.getChangeSupport().removeStateChangeListener(listener);
- }
-
- protected final void fireStateChanged() {
- this.getChangeSupport().fireStateChanged();
- }
-
- protected final void fireStateChanged(StateChangeEvent event) {
- this.getChangeSupport().fireStateChanged(event);
- }
-
-
- // ********** property change support **********
-
- public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
- this.getChangeSupport().addPropertyChangeListener(listener);
- }
-
- public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- this.getChangeSupport().addPropertyChangeListener(propertyName, listener);
- }
-
- public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
- this.getChangeSupport().removePropertyChangeListener(listener);
- }
-
- public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- this.getChangeSupport().removePropertyChangeListener(propertyName, listener);
- }
-
- protected final void firePropertyChanged(String propertyName, Object oldValue, Object newValue) {
- this.getChangeSupport().firePropertyChanged(propertyName, oldValue, newValue);
- }
-
- protected final void firePropertyChanged(String propertyName, int oldValue, int newValue) {
- this.getChangeSupport().firePropertyChanged(propertyName, oldValue, newValue);
- }
-
- protected final void firePropertyChanged(String propertyName, boolean oldValue, boolean newValue) {
- this.getChangeSupport().firePropertyChanged(propertyName, oldValue, newValue);
- }
-
- protected final void firePropertyChanged(String propertyName, Object newValue) {
- this.getChangeSupport().firePropertyChanged(propertyName, null, newValue);
- }
-
- protected final void firePropertyChanged(PropertyChangeEvent event) {
- this.getChangeSupport().firePropertyChanged(event);
- }
-
-
- // ********** collection change support **********
-
- public synchronized void addCollectionChangeListener(CollectionChangeListener listener) {
- this.getChangeSupport().addCollectionChangeListener(listener);
- }
-
- public synchronized void addCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- this.getChangeSupport().addCollectionChangeListener(collectionName, listener);
- }
-
- public synchronized void removeCollectionChangeListener(CollectionChangeListener listener) {
- this.getChangeSupport().removeCollectionChangeListener(listener);
- }
-
- public synchronized void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- this.getChangeSupport().removeCollectionChangeListener(collectionName, listener);
- }
-
- protected final void fireItemAdded(String collectionName, Object addedItem) {
- this.getChangeSupport().fireItemAdded(collectionName, addedItem);
- }
-
- protected final void fireItemsAdded(String collectionName, Collection<?> addedItems) {
- this.getChangeSupport().fireItemsAdded(collectionName, addedItems);
- }
-
- protected final void fireItemsAdded(CollectionChangeEvent event) {
- this.getChangeSupport().fireItemsAdded(event);
- }
-
- protected final void fireItemRemoved(String collectionName, Object removedItem) {
- this.getChangeSupport().fireItemRemoved(collectionName, removedItem);
- }
-
- protected final void fireItemsRemoved(String collectionName, Collection<?> removedItems) {
- this.getChangeSupport().fireItemsRemoved(collectionName, removedItems);
- }
-
- protected final void fireItemsRemoved(CollectionChangeEvent event) {
- this.getChangeSupport().fireItemsRemoved(event);
- }
-
- protected final void fireCollectionCleared(String collectionName) {
- this.getChangeSupport().fireCollectionCleared(collectionName);
- }
-
- protected final void fireCollectionCleared(CollectionChangeEvent event) {
- this.getChangeSupport().fireCollectionCleared(event);
- }
-
- protected final void fireCollectionChanged(String collectionName) {
- this.getChangeSupport().fireCollectionChanged(collectionName);
- }
-
- protected final void fireCollectionChanged(CollectionChangeEvent event) {
- this.getChangeSupport().fireCollectionChanged(event);
- }
-
- /**
- * Convenience method.
- * Add the specified item to the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#add(Object)
- */
- protected <E> boolean addItemToCollection(E item, Collection<E> collection, String collectionName) {
- if (collection.add(item)) {
- this.fireItemAdded(collectionName, item);
- return true;
- }
- return false;
- }
-
- /**
- * Convenience method.
- * Add the specified items to the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether collection changed.
- * @see java.util.Collection#addAll(java.util.Collection)
- */
- protected <E> boolean addItemsToCollection(E[] items, Collection<E> collection, String collectionName) {
- return this.addItemsToCollection(new ArrayIterator<E>(items), collection, collectionName);
- }
-
- /**
- * Convenience method.
- * Add the specified items to the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether collection changed.
- * @see java.util.Collection#addAll(java.util.Collection)
- */
- protected <E> boolean addItemsToCollection(Iterable<? extends E> items, Collection<E> collection, String collectionName) {
- return this.addItemsToCollection(items.iterator(), collection, collectionName);
- }
-
- /**
- * Convenience method.
- * Add the specified items to the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether collection changed.
- * @see java.util.Collection#addAll(java.util.Collection)
- */
- protected <E> boolean addItemsToCollection(Iterator<? extends E> items, Collection<E> collection, String collectionName) {
- Collection<E> addedItems = null;
- while (items.hasNext()) {
- E item = items.next();
- if (collection.add(item)) {
- if (addedItems == null) {
- addedItems = new ArrayList<E>();
- }
- addedItems.add(item);
- }
- }
- if (addedItems != null) {
- this.fireItemsAdded(collectionName, addedItems);
- return true;
- }
- return false;
- }
-
- /**
- * Convenience method.
- * Remove the specified item from the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#remove(Object)
- */
- protected boolean removeItemFromCollection(Object item, Collection<?> collection, String collectionName) {
- if (collection.remove(item)) {
- this.fireItemRemoved(collectionName, item);
- return true;
- }
- return false;
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#removeAll(java.util.Collection)
- */
- protected boolean removeItemsFromCollection(Object[] items, Collection<?> collection, String collectionName) {
- return this.removeItemsFromCollection(new ArrayIterator<Object>(items), collection, collectionName);
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#removeAll(java.util.Collection)
- */
- protected boolean removeItemsFromCollection(Iterable<?> items, Collection<?> collection, String collectionName) {
- return this.removeItemsFromCollection(items.iterator(), collection, collectionName);
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#removeAll(java.util.Collection)
- */
- protected boolean removeItemsFromCollection(Iterator<?> items, Collection<?> collection, String collectionName) {
- Collection<?> items2 = CollectionTools.collection(items);
- items2.retainAll(collection);
- boolean changed = collection.removeAll(items2);
-
- if ( ! items2.isEmpty()) {
- this.fireItemsRemoved(collectionName, items2);
- }
- return changed;
- }
-
- /**
- * Convenience method.
- * Retain the specified items in the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#retainAll(java.util.Collection)
- */
- protected boolean retainItemsInCollection(Object[] items, Collection<?> collection, String collectionName) {
- return this.retainItemsInCollection(new ArrayIterator<Object>(items), collection, collectionName);
- }
-
- /**
- * Convenience method.
- * Retain the specified items in the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#retainAll(java.util.Collection)
- */
- protected boolean retainItemsInCollection(Iterable<?> items, Collection<?> collection, String collectionName) {
- return this.retainItemsInCollection(items.iterator(), collection, collectionName);
- }
-
- /**
- * Convenience method.
- * Retain the specified items in the specified bound collection
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.Collection#retainAll(java.util.Collection)
- */
- protected boolean retainItemsInCollection(Iterator<?> items, Collection<?> collection, String collectionName) {
- Collection<?> items2 = CollectionTools.collection(items);
- Collection<?> removedItems = CollectionTools.collection(collection);
- removedItems.removeAll(items2);
- boolean changed = collection.retainAll(items2);
-
- if ( ! removedItems.isEmpty()) {
- this.fireItemsRemoved(collectionName, removedItems);
- }
- return changed;
- }
-
- /**
- * Convenience method.
- * Clear the entire collection
- * and fire the appropriate event if necessary.
- * Return whether the list changed.
- * @see java.util.Collection#clear()
- */
- protected boolean clearCollection(Collection<?> collection, String collectionName) {
- if (collection.isEmpty()) {
- return false;
- }
- collection.clear();
- this.fireCollectionCleared(collectionName);
- return true;
- }
-
- /**
- * Convenience method.
- * Synchronize the collection with the specified new collection,
- * making a minimum number of removes and adds.
- * Return whether the collection changed.
- */
- protected <E> boolean synchronizeCollection(Collection<E> newCollection, Collection<E> collection, String collectionName) {
- if (newCollection.isEmpty()) {
- return this.clearCollection(collection, collectionName);
- }
-
- if (collection.isEmpty()) {
- return this.addItemsToCollection(newCollection, collection, collectionName);
- }
-
- boolean changed = false;
- Collection<E> removeItems = new HashBag<E>(collection);
- removeItems.removeAll(newCollection);
- changed |= this.removeItemsFromCollection(removeItems, collection, collectionName);
-
- Collection<E> addItems = new HashBag<E>(newCollection);
- addItems.removeAll(collection);
- changed |= this.addItemsToCollection(addItems, collection, collectionName);
-
- return changed;
- }
-
- /**
- * Convenience method.
- * Synchronize the collection with the specified new collection,
- * making a minimum number of removes and adds.
- * Return whether the collection changed.
- */
- protected <E> boolean synchronizeCollection(Iterator<E> newItems, Collection<E> collection, String collectionName) {
- return this.synchronizeCollection(CollectionTools.collection(newItems), collection, collectionName);
- }
-
-
- // ********** list change support **********
-
- public synchronized void addListChangeListener(ListChangeListener listener) {
- this.getChangeSupport().addListChangeListener(listener);
- }
-
- public synchronized void addListChangeListener(String listName, ListChangeListener listener) {
- this.getChangeSupport().addListChangeListener(listName, listener);
- }
-
- public synchronized void removeListChangeListener(ListChangeListener listener) {
- this.getChangeSupport().removeListChangeListener(listener);
- }
-
- public synchronized void removeListChangeListener(String listName, ListChangeListener listener) {
- this.getChangeSupport().removeListChangeListener(listName, listener);
- }
-
- protected final void fireItemAdded(String listName, int index, Object addedItem) {
- this.getChangeSupport().fireItemAdded(listName, index, addedItem);
- }
-
- protected final void fireItemsAdded(String listName, int index, List<?> addedItems) {
- this.getChangeSupport().fireItemsAdded(listName, index, addedItems);
- }
-
- protected final void fireItemsAdded(ListChangeEvent event) {
- this.getChangeSupport().fireItemsAdded(event);
- }
-
- protected final void fireItemRemoved(String listName, int index, Object removedItem) {
- this.getChangeSupport().fireItemRemoved(listName, index, removedItem);
- }
-
- protected final void fireItemsRemoved(String listName, int index, List<?> removedItems) {
- this.getChangeSupport().fireItemsRemoved(listName, index, removedItems);
- }
-
- protected final void fireItemsRemoved(ListChangeEvent event) {
- this.getChangeSupport().fireItemsRemoved(event);
- }
-
- protected final void fireItemReplaced(String listName, int index, Object newItem, Object replacedItem) {
- this.getChangeSupport().fireItemReplaced(listName, index, newItem, replacedItem);
- }
-
- protected final <E> void fireItemsReplaced(String listName, int index, List<? extends E> newItems, List<E> replacedItems) {
- this.getChangeSupport().fireItemsReplaced(listName, index, newItems, replacedItems);
- }
-
- protected final void fireItemsReplaced(ListChangeEvent event) {
- this.getChangeSupport().fireItemsReplaced(event);
- }
-
- protected final void fireItemMoved(String listName, int targetIndex, int sourceIndex) {
- this.getChangeSupport().fireItemMoved(listName, targetIndex, sourceIndex);
- }
-
- protected final <E> void fireItemsMoved(String listName, int targetIndex, int sourceIndex, int length) {
- this.getChangeSupport().fireItemsMoved(listName, targetIndex, sourceIndex, length);
- }
-
- protected final void fireItemsMoved(ListChangeEvent event) {
- this.getChangeSupport().fireItemsMoved(event);
- }
-
- protected final void fireListCleared(String listName) {
- this.getChangeSupport().fireListCleared(listName);
- }
-
- protected final void fireListCleared(ListChangeEvent event) {
- this.getChangeSupport().fireListCleared(event);
- }
-
- protected final void fireListChanged(String listName) {
- this.getChangeSupport().fireListChanged(listName);
- }
-
- protected final void fireListChanged(ListChangeEvent event) {
- this.getChangeSupport().fireListChanged(event);
- }
-
- /**
- * Convenience method.
- * Add the specified item to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#add(int, Object)
- */
- protected <E> void addItemToList(int index, E item, List<E> list, String listName) {
- list.add(index, item);
- this.fireItemAdded(listName, index, item);
- }
-
- /**
- * Convenience method.
- * Add the specified item to the end of the specified bound list
- * and fire the appropriate event if necessary.
- * Return whether list changed.
- * @see java.util.List#add(Object)
- */
- protected <E> boolean addItemToList(E item, List<E> list, String listName) {
- if (list.add(item)) {
- this.fireItemAdded(listName, list.size() - 1, item);
- return true;
- }
- return false;
- }
-
- /**
- * Convenience method.
- * Add the specified items to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#addAll(int, java.util.Collection)
- */
- protected <E> boolean addItemsToList(int index, E[] items, List<E> list, String listName) {
- return this.addItemsToList(index, new ArrayIterator<E>(items), list, listName);
- }
-
- /**
- * Convenience method.
- * Add the specified items to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#addAll(int, java.util.Collection)
- */
- protected <E> boolean addItemsToList(int index, Iterable<? extends E> items, List<E> list, String listName) {
- return this.addItemsToList(index, items.iterator(), list, listName);
- }
-
- /**
- * Convenience method.
- * Add the specified items to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#addAll(int, java.util.Collection)
- */
- protected <E> boolean addItemsToList(int index, Iterator<? extends E> items, List<E> list, String listName) {
- List<E> items2 = CollectionTools.list(items);
- if (list.addAll(index, items2)) {
- this.fireItemsAdded(listName, index, items2);
- return true;
- }
- return false;
- }
-
- /**
- * Convenience method.
- * Add the specified items to the end of to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#addAll(java.util.Collection)
- */
- protected <E> boolean addItemsToList(E[] items, List<E> list, String listName) {
- return this.addItemsToList(new ArrayIterator<E>(items), list, listName);
- }
-
- /**
- * Convenience method.
- * Add the specified items to the end of to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#addAll(java.util.Collection)
- */
- protected <E> boolean addItemsToList(Iterable<? extends E> items, List<E> list, String listName) {
- return this.addItemsToList(items.iterator(), list, listName);
- }
-
- /**
- * Convenience method.
- * Add the specified items to the end of to the specified bound list
- * and fire the appropriate event if necessary.
- * @see java.util.List#addAll(java.util.Collection)
- */
- protected <E> boolean addItemsToList(Iterator<? extends E> items, List<E> list, String listName) {
- List<E> items2 = CollectionTools.list(items);
- int index = list.size();
- if (list.addAll(items2)) {
- this.fireItemsAdded(listName, index, items2);
- return true;
- }
- return false; // empty list of items added
- }
-
- /**
- * Convenience method.
- * Remove the specified item from the specified bound list
- * and fire the appropriate event if necessary.
- * Return the removed item.
- * @see java.util.List#remove(int)
- */
- protected <E> E removeItemFromList(int index, List<E> list, String listName) {
- E item = list.remove(index);
- this.fireItemRemoved(listName, index, item);
- return item;
- }
-
- /**
- * Convenience method.
- * Remove the specified item from the specified bound list
- * and fire the appropriate event if necessary.
- * Return the removed item.
- * @see java.util.List#remove(Object)
- */
- protected boolean removeItemFromList(Object item, List<?> list, String listName) {
- int index = list.indexOf(item);
- if (index == -1) {
- return false;
- }
- list.remove(index);
- this.fireItemRemoved(listName, index, item);
- return true;
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound list
- * and fire the appropriate event if necessary.
- * Return the removed items.
- * @see java.util.List#remove(int)
- */
- protected <E> List<E> removeItemsFromList(int index, int length, List<E> list, String listName) {
- List<E> subList = list.subList(index, index + length);
- List<E> removedItems = new ArrayList<E>(subList);
- subList.clear();
- this.fireItemsRemoved(listName, index, removedItems);
- return removedItems;
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound list
- * and fire the appropriate event if necessary.
- * Return the removed items.
- * @see java.util.List#removeAll(java.util.Collection)
- */
- protected boolean removeItemsFromList(Object[] items, List<?> list, String listName) {
- return this.removeItemsFromList(new ArrayIterator<Object>(items), list, listName);
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound list
- * and fire the appropriate event if necessary.
- * Return the removed items.
- * @see java.util.List#removeAll(java.util.Collection)
- */
- protected boolean removeItemsFromList(Iterable<?> items, List<?> list, String listName) {
- return this.removeItemsFromList(items.iterator(), list, listName);
- }
-
- /**
- * Convenience method.
- * Remove the specified items from the specified bound list
- * and fire the appropriate event if necessary.
- * Return the removed items.
- * @see java.util.List#removeAll(java.util.Collection)
- */
- protected boolean removeItemsFromList(Iterator<?> items, List<?> list, String listName) {
- boolean changed = false;
- while (items.hasNext()) {
- changed |= this.removeItemFromList(items.next(), list, listName);
- }
- return changed;
- }
-
- /**
- * Convenience method.
- * Retain the specified items in the specified bound list
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.List#retainAll(java.util.Collection)
- */
- protected boolean retainItemsInList(Object[] items, List<?> list, String listName) {
- return this.retainItemsInList(new ArrayIterator<Object>(items), list, listName);
- }
-
- /**
- * Convenience method.
- * Retain the specified items in the specified bound list
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.List#retainAll(java.util.Collection)
- */
- protected boolean retainItemsInList(Iterable<?> items, List<?> list, String listName) {
- return this.retainItemsInList(items.iterator(), list, listName);
- }
-
- /**
- * Convenience method.
- * Retain the specified items in the specified bound list
- * and fire the appropriate event if necessary.
- * Return whether the collection changed.
- * @see java.util.List#retainAll(java.util.Collection)
- */
- protected boolean retainItemsInList(Iterator<?> items, List<?> list, String listName) {
- Collection<?> items2 = CollectionTools.collection(items);
- Collection<?> removedItems = CollectionTools.collection(list);
- removedItems.removeAll(items2);
- return this.removeItemsFromList(removedItems, list, listName);
- }
-
- /**
- * Convenience method.
- * Set the specified item in the specified bound list
- * and fire the appropriate event if necessary.
- * Return the replaced item.
- * @see java.util.List#set(int, Object)
- */
- protected <E> E setItemInList(int index, E item, List<E> list, String listName) {
- E replacedItem = list.set(index, item);
- this.fireItemReplaced(listName, index, item, replacedItem);
- return replacedItem;
- }
-
- /**
- * Convenience method.
- * Replace the specified item in the specified bound list
- * and fire the appropriate event if necessary.
- * Return the replaced item.
- * @see java.util.List#set(int, Object)
- */
- protected <E> E replaceItemInList(E oldItem, E newItem, List<E> list, String listName) {
- return this.setItemInList(list.indexOf(oldItem), newItem, list, listName);
- }
-
- /**
- * Convenience method.
- * Set the specified items in the specified bound list
- * and fire the appropriate event if necessary.
- * Return the replaced items.
- * @see java.util.List#set(int, Object)
- */
- protected <E> List<E> setItemsInList(int index, E[] items, List<E> list, String listName) {
- return this.setItemsInList(index, Arrays.asList(items), list, listName);
- }
-
- /**
- * Convenience method.
- * Set the specified items in the specified bound list
- * and fire the appropriate event if necessary.
- * Return the replaced items.
- * @see java.util.List#set(int, Object)
- */
- protected <E> List<E> setItemsInList(int index, List<? extends E> items, List<E> list, String listName) {
- List<E> subList = list.subList(index, index + items.size());
- List<E> replacedItems = new ArrayList<E>(subList);
- for (int i = 0; i < items.size(); i++) {
- subList.set(i, items.get(i));
- }
- this.fireItemsReplaced(listName, index, items, replacedItems);
- return replacedItems;
- }
-
- /**
- * Convenience method.
- * Move items in the specified list from the specified source index to the
- * specified target index for the specified length.
- */
- protected <E> void moveItemsInList(int targetIndex, int sourceIndex, int length, List<E> list, String listName) {
- CollectionTools.move(list, targetIndex, sourceIndex, length);
- this.fireItemsMoved(listName, targetIndex, sourceIndex, length);
- }
-
- /**
- * Convenience method.
- * Move an item in the specified list from the specified source index to the
- * specified target index.
- */
- protected <E> void moveItemInList(int targetIndex, int sourceIndex, List<E> list, String listName) {
- CollectionTools.move(list, targetIndex, sourceIndex);
- this.fireItemMoved(listName, targetIndex, sourceIndex);
- }
-
- /**
- * Convenience method.
- * Clear the entire list
- * and fire the appropriate event if necessary.
- * Return whether the list changed.
- * @see java.util.List#clear()
- */
- protected boolean clearList(List<?> list, String listName) {
- if (list.isEmpty()) {
- return false;
- }
- list.clear();
- this.fireListCleared(listName);
- return true;
- }
-
-
- // ********** tree change support **********
-
- public synchronized void addTreeChangeListener(TreeChangeListener listener) {
- this.getChangeSupport().addTreeChangeListener(listener);
- }
-
- public synchronized void addTreeChangeListener(String treeName, TreeChangeListener listener) {
- this.getChangeSupport().addTreeChangeListener(treeName, listener);
- }
-
- public synchronized void removeTreeChangeListener(TreeChangeListener listener) {
- this.getChangeSupport().removeTreeChangeListener(listener);
- }
-
- public synchronized void removeTreeChangeListener(String treeName, TreeChangeListener listener) {
- this.getChangeSupport().removeTreeChangeListener(treeName, listener);
- }
-
- protected final void fireNodeAdded(String treeName, Object[] path) {
- this.getChangeSupport().fireNodeAdded(treeName, path);
- }
-
- protected final void fireNodeAdded(TreeChangeEvent event) {
- this.getChangeSupport().fireNodeAdded(event);
- }
-
- protected final void fireNodeRemoved(String treeName, Object[] path) {
- this.getChangeSupport().fireNodeRemoved(treeName, path);
- }
-
- protected final void fireNodeRemoved(TreeChangeEvent event) {
- this.getChangeSupport().fireNodeRemoved(event);
- }
-
- protected final void fireTreeCleared(String treeName) {
- this.getChangeSupport().fireTreeCleared(treeName);
- }
-
- protected final void fireTreeCleared(TreeChangeEvent event) {
- this.getChangeSupport().fireTreeCleared(event);
- }
-
- protected final void fireTreeChanged(String treeName) {
- this.getChangeSupport().fireTreeChanged(treeName);
- }
-
- protected final void fireTreeChanged(String treeName, Object[] path) {
- this.getChangeSupport().fireTreeChanged(treeName, path);
- }
-
- protected final void fireTreeChanged(TreeChangeEvent event) {
- this.getChangeSupport().fireTreeChanged(event);
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether there are any state change listeners.
- */
- public boolean hasAnyStateChangeListeners() {
- return this.getChangeSupport().hasAnyStateChangeListeners();
- }
-
- /**
- * Return whether there are no state change listeners.
- */
- public boolean hasNoStateChangeListeners() {
- return ! this.hasAnyStateChangeListeners();
- }
-
- /**
- * Return whether there are any property change listeners for a specific property.
- */
- public boolean hasAnyPropertyChangeListeners(String propertyName) {
- return this.getChangeSupport().hasAnyPropertyChangeListeners(propertyName);
- }
-
- /**
- * Return whether there are any property change listeners for a specific property.
- */
- public boolean hasNoPropertyChangeListeners(String propertyName) {
- return ! this.hasAnyPropertyChangeListeners(propertyName);
- }
-
- /**
- * Return whether there are any collection change listeners for a specific collection.
- */
- public boolean hasAnyCollectionChangeListeners(String collectionName) {
- return this.getChangeSupport().hasAnyCollectionChangeListeners(collectionName);
- }
-
- /**
- * Return whether there are any collection change listeners for a specific collection.
- */
- public boolean hasNoCollectionChangeListeners(String collectionName) {
- return ! this.hasAnyCollectionChangeListeners(collectionName);
- }
-
- /**
- * Return whether there are any list change listeners for a specific list.
- */
- public boolean hasAnyListChangeListeners(String listName) {
- return this.getChangeSupport().hasAnyListChangeListeners(listName);
- }
-
- /**
- * Return whether there are any list change listeners for a specific list.
- */
- public boolean hasNoListChangeListeners(String listName) {
- return ! this.hasAnyListChangeListeners(listName);
- }
-
- /**
- * Return whether there are any tree change listeners for a specific tree.
- */
- public boolean hasAnyTreeChangeListeners(String treeName) {
- return this.getChangeSupport().hasAnyTreeChangeListeners(treeName);
- }
-
- /**
- * Return whether there are any tree change listeners for a specific tree.
- */
- public boolean hasNoTreeChangeListeners(String treeName) {
- return ! this.hasAnyTreeChangeListeners(treeName);
- }
-
-
- // ********** convenience methods **********
-
- /**
- * Return whether the values are equal, with the appropriate null checks.
- * Convenience method for checking whether an attribute value has changed.
- *
- * DO NOT use this to determine whether to fire a change notification,
- * ChangeSupport already does that.
- */
- protected final boolean valuesAreEqual(Object value1, Object value2) {
- return this.getChangeSupport().valuesAreEqual(value1, value2);
- }
- protected final boolean attributeValueHasNotChanged(Object oldValue, Object newValue) {
- return this.valuesAreEqual(oldValue, newValue);
- }
-
-
- /**
- * Return whether the values are different, with the appropriate null checks.
- * Convenience method for checking whether an attribute value has changed.
- *
- * DO NOT use this to determine whether to fire a change notification,
- * ChangeSupport already does that.
- *
- * For example, after firing the change notification, you can use this method
- * to decide if some other, related, piece of state needs to be synchronized
- * with the state that just changed.
- */
- protected final boolean valuesAreDifferent(Object value1, Object value2) {
- return this.getChangeSupport().valuesAreDifferent(value1, value2);
- }
- protected final boolean attributeValueHasChanged(Object oldValue, Object newValue) {
- return this.valuesAreDifferent(oldValue, newValue);
- }
-
-
- // ********** Object overrides **********
-
- /**
- * Although cloning models is usually not a Good Idea,
- * we should at least support it properly.
- */
- @Override
- protected AbstractModel clone() throws CloneNotSupportedException {
- AbstractModel clone = (AbstractModel) super.clone();
- clone.postClone();
- return clone;
- }
-
- /**
- * Perform any post-clone processing necessary to
- * successfully disconnect the clone from the original.
- * When this method is called on the clone, the clone
- * is a "shallow" copy of the original (i.e. the clone
- * shares all its instance variables with the original).
- */
- protected void postClone() {
- // clear out change support - models do not share listeners
- this.changeSupport = null;
- // when you override this method, don't forget to include:
- // super.postClone();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- StringTools.buildSimpleToStringOn(this, sb);
- sb.append(" ("); //$NON-NLS-1$
- this.toString(sb);
- sb.append(')');
- return sb.toString();
- }
-
- /**
- * make this public so one model can call a nested model's
- * #toString(StringBuilder)
- */
- public void toString(@SuppressWarnings("unused") StringBuilder sb) {
- // subclasses should override this to do something a bit more helpful
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/CallbackChangeSupport.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/CallbackChangeSupport.java
deleted file mode 100644
index e85a27bbe1..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/CallbackChangeSupport.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model;
-
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * This change support class will notify the source when one of the source's
- * aspects has changed.
- */
-public class CallbackChangeSupport extends ChangeSupport {
- private static final long serialVersionUID = 1L;
-
- public CallbackChangeSupport(Source source) {
- super(source);
- }
-
- protected Source source() {
- return (Source) this.source;
- }
-
- @Override
- protected ChangeSupport buildChildChangeSupport() {
- return new Child(this.source());
- }
-
- @Override
- protected void sourceChanged(String aspectName) {
- super.sourceChanged(aspectName);
- this.source().aspectChanged(aspectName);
- }
-
-
- // ********** child change support **********
-
- /**
- * The aspect-specific change support class does not need to
- * notify the source node of changes (the parent will take care of that);
- * nor does it need to build "grandchildren" change support objects.
- */
- protected static class Child extends ChangeSupport {
- private static final long serialVersionUID = 1L;
-
- public Child(Source source) {
- super(source);
- }
-
- protected Source source() {
- return (Source) this.source;
- }
-
- @Override
- protected ChangeSupport buildChildChangeSupport() {
- // there are no grandchildren
- throw new UnsupportedOperationException();
- }
-
- }
-
-
- // ********** source interface **********
-
- /**
- * The callback change support source must implement this interface so it
- * can be notified of any aspect changes.
- */
- public interface Source extends Model {
-
- /**
- * The specified aspect changed.
- */
- void aspectChanged(String aspectName);
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/ChangeSupport.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/ChangeSupport.java
deleted file mode 100644
index 3150f612bc..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/ChangeSupport.java
+++ /dev/null
@@ -1,2363 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.lang.reflect.Array;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-
-/**
- * Support object that can be used by implementors of the Model interface.
- * It provides for state, property, collection, list, and tree change notifications to
- * listeners.
- *
- * NB: There is lots of copy-n-paste code in this class. Nearly all of this duplication
- * is an effort to prevent the unnecessary creation of new objects (typically event
- * objects). Since many events are fired when there are no listeners, we postpone
- * the creation of event objects until we know we have interested listeners.
- * Most methods have the "non-duplicated" version of the method body commented
- * out at the top of the current method body.
- * The hope was that this class would prove to be fairly static and the duplicated
- * code would not prove onerous; but that has not proven to be
- * the case, as we have added support for "state" changes, "dirty" notification,
- * and custom "notifiers", with more to come, I'm sure.... ~bjv
- *
- * NB2: This class will check to see if, during the firing of events, a listener
- * on the original, cloned, list of listeners has been removed from the master
- * list of listeners *before* it is notified. If the listener has been removed
- * "concurrently" it will *not* be notified. (See the code that uses the
- * 'stillListening' local boolean flag.)
- *
- * NB3: Any listener that is added during the firing of events will *not* be
- * also notified.
- *
- * NB4: This class is serializable, but it will only write out listeners that
- * are also serializable while silently leaving behind listeners that are not.
- *
- * TODO fire a state change event with *every* change?
- * TODO use objects (IDs?) instead of strings to identify aspects?
- */
-public class ChangeSupport
- implements Serializable
-{
-
- /** The object to be provided as the "source" for any generated events. */
- protected final Model source;
-
- /** Associate a listener class to a collection of "generic" listeners for that class. */
- private transient GenericListenerList[] genericListeners = EMPTY_GENERIC_LISTENERS;
- private static final GenericListenerList[] EMPTY_GENERIC_LISTENERS = new GenericListenerList[0];
-
- /** Associate aspect names to child change support objects. */
- private AspectChild[] aspectChildren = EMPTY_ASPECT_CHILDREN;
- private static final AspectChild[] EMPTY_ASPECT_CHILDREN = new AspectChild[0];
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructor **********
-
- /**
- * Construct support for the specified source of change events.
- * The source cannot be null.
- */
- public ChangeSupport(Model source) {
- super();
- if (source == null) {
- throw new NullPointerException();
- }
- this.source = source;
- }
-
-
- // ********** internal behavior **********
-
- /**
- * Add a "generic" listener that listens to all events appropriate to that
- * listener, regardless of the aspect name associated with that event.
- * The listener cannot be null.
- */
- protected <T extends ChangeListener> void addListener(Class<T> listenerClass, T listener) {
- if (listener == null) {
- throw new NullPointerException(); // better sooner than later
- }
- synchronized (this) {
- GenericListenerList gll = this.genericListenerList(listenerClass);
- if (gll == null) {
- this.addGenericListenerList(listenerClass, listener);
- } else {
- gll.addListener(listener);
- }
- }
- }
-
- /**
- * Return the "generic" listener list for the specified listener class.
- * Return null if the list is not present.
- */
- protected GenericListenerList genericListenerList(Class<? extends ChangeListener> listenerClass) {
- for (GenericListenerList gll : this.genericListeners) {
- if (gll.listenerClass == listenerClass) {
- return gll;
- }
- }
- return null;
- }
-
- /**
- * Add the "generic" listener list for the specified listener class.
- * Return the newly-built generic listener list.
- */
- protected <T extends ChangeListener> GenericListenerList addGenericListenerList(Class<T> listenerClass, T listener) {
- GenericListenerList gll = new GenericListenerList(listenerClass, listener);
- this.genericListeners = CollectionTools.add(this.genericListeners, gll);
- return gll;
- }
-
- /**
- * Adds a listener that listens to all events appropriate to that listener,
- * and only to those events carrying the aspect name specified.
- * The aspect name cannot be null and the listener cannot be null.
- */
- protected <T extends ChangeListener> void addListener(String aspectName, Class<T> listenerClass, T listener) {
- if ((aspectName == null) || (listener == null)) {
- throw new NullPointerException(); // better sooner than later
- }
- synchronized (this) {
- ChangeSupport child = this.child(aspectName);
- if (child == null) {
- child = this.addChild(aspectName);
- }
- child.addListener(listenerClass, listener);
- }
- }
-
- /**
- * Return the child change support for the specified aspect name.
- * Return null if the aspect name is null or the child is not present.
- */
- protected ChangeSupport child(String aspectName) {
- // put in a null check to simplify calling code
- if (aspectName == null) {
- return null;
- }
- for (AspectChild aspectChild : this.aspectChildren) {
- if (aspectChild.aspectName == aspectName) {
- return aspectChild.child;
- }
- }
- return null;
- }
-
- /**
- * Add the child change support for the specified aspect name.
- * Return the newly-built child change support.
- */
- protected ChangeSupport addChild(String aspectName) {
- ChangeSupport child = this.buildChildChangeSupport();
- this.aspectChildren = CollectionTools.add(this.aspectChildren, new AspectChild(aspectName, child));
- return child;
- }
-
- /**
- * Build and return a child change support to hold aspect-specific listeners.
- */
- protected ChangeSupport buildChildChangeSupport() {
- return new ChangeSupport(this.source);
- }
-
- /**
- * Removes a "generic" listener that has been registered for all events
- * appropriate to that listener.
- */
- protected <T extends ChangeListener> void removeListener(Class<T> listenerClass, T listener) {
- synchronized (this) {
- GenericListenerList gll = this.genericListenerList(listenerClass);
- if (gll == null) {
- throw new IllegalArgumentException("listener not registered"); //$NON-NLS-1$
- }
- if ( ! gll.removeListener(listener)) { // leave the GLL, even if it is empty?
- throw new IllegalArgumentException("listener not registered: " + listener); //$NON-NLS-1$
- }
- }
- }
-
- /**
- * Removes a listener that has been registered for appropriate
- * events carrying the specified aspect name.
- */
- protected <T extends ChangeListener> void removeListener(String aspectName, Class<T> listenerClass, T listener) {
- synchronized (this) {
- ChangeSupport child = this.child(aspectName);
- if (child == null) {
- throw new IllegalArgumentException("listener not registered"); //$NON-NLS-1$
- }
- child.removeListener(listenerClass, listener); // leave the child, even if it is empty?
- }
- }
-
-
- // ********** internal queries **********
-
- /**
- * Return the "generic" listeners for the specified listener class.
- * Return null if there are no listeners.
- */
- protected ChangeListener[] listeners(Class<? extends ChangeListener> listenerClass) {
- GenericListenerList gll = this.genericListenerList(listenerClass);
- return (gll == null) ? null : gll.listeners;
- }
-
- /**
- * Return whether there are any "generic" listeners for the specified
- * listener class.
- */
- protected synchronized <T extends ChangeListener> boolean hasAnyListeners(Class<T> listenerClass) {
- GenericListenerList gll = this.genericListenerList(listenerClass);
- return (gll != null) && gll.hasListeners();
- }
-
- /**
- * Return whether there are no "generic" listeners for the specified
- * listener class.
- */
- protected <T extends ChangeListener> boolean hasNoListeners(Class<T> listenerClass) {
- return ! this.hasAnyListeners(listenerClass);
- }
-
- /**
- * Return whether there are any listeners for the specified
- * listener class and aspect name.
- */
- protected synchronized boolean hasAnyListeners(Class<? extends ChangeListener> listenerClass, String aspectName) {
- if (this.hasAnyListeners(listenerClass)) {
- return true; // there's a "generic" listener
- }
- ChangeSupport child = this.child(aspectName);
- return (child != null) &&
- child.hasAnyListeners(listenerClass);
- }
-
- /**
- * Return whether there are no "generic" listeners for the specified
- * listener class and aspect name.
- */
- protected <T extends ChangeListener> boolean hasNoListeners(Class<T> listenerClass, String aspectName) {
- return ! this.hasAnyListeners(listenerClass, aspectName);
- }
-
-
- // ********** behavior **********
-
- /**
- * The specified aspect of the source has changed;
- * override this method to perform things like setting a
- * dirty flag or validating the source's state.
- * The aspect ID will be null if a "state change" occurred.
- */
- protected void sourceChanged(@SuppressWarnings("unused") String aspectName) {
- // the default is to do nothing
- }
-
-
- // ********** state change support **********
-
- protected static final Class<StateChangeListener> STATE_CHANGE_LISTENER_CLASS = StateChangeListener.class;
-
- /**
- * Add a state change listener.
- */
- public void addStateChangeListener(StateChangeListener listener) {
- this.addListener(STATE_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a state change listener.
- */
- public void removeStateChangeListener(StateChangeListener listener) {
- this.removeListener(STATE_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Return whether there are any state change listeners.
- */
- public boolean hasAnyStateChangeListeners() {
- return this.hasAnyListeners(STATE_CHANGE_LISTENER_CLASS);
- }
-
- private StateChangeListener[] stateChangeListeners() {
- return (StateChangeListener[]) this.listeners(STATE_CHANGE_LISTENER_CLASS);
- }
-
- /**
- * Fire the specified state change event to any registered listeners.
- */
- public void fireStateChanged(StateChangeEvent event) {
-
- StateChangeListener[] targets = null;
-
- synchronized (this) {
- StateChangeListener[] stateChangeListeners = this.stateChangeListeners();
- if (stateChangeListeners != null) {
- targets = stateChangeListeners.clone();
- }
- }
-
- if (targets != null) {
- for (StateChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.stateChangeListeners(), target);
- }
- if (stillListening) {
- target.stateChanged(event);
- }
- }
- }
-
- this.sourceChanged(null);
- }
-
- /**
- * Report a generic state change event to any registered state change
- * listeners.
- */
- public void fireStateChanged() {
-// this.fireStateChange(new StateChangeEvent(this.source));
-
- StateChangeListener[] targets = null;
-
- synchronized (this) {
- StateChangeListener[] stateChangeListeners = this.stateChangeListeners();
- if (stateChangeListeners != null) {
- targets = stateChangeListeners.clone();
- }
- }
-
- if (targets != null) {
- StateChangeEvent event = null;
- for (StateChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.stateChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new StateChangeEvent(this.source);
- }
- target.stateChanged(event);
- }
- }
- }
-
- this.sourceChanged(null);
- }
-
-
- // ********** property change support **********
-
- protected static final Class<PropertyChangeListener> PROPERTY_CHANGE_LISTENER_CLASS = PropertyChangeListener.class;
-
- /**
- * Return whether the values are equal, with the appropriate null checks.
- * Convenience method for checking whether an attribute value has changed.
- */
- public boolean valuesAreEqual(Object value1, Object value2) {
- if ((value1 == null) && (value2 == null)) {
- return true; // both are null
- }
- if ((value1 == null) || (value2 == null)) {
- return false; // one is null but the other is not
- }
- return value1.equals(value2);
- }
-
- /**
- * Return whether the values are different, with the appropriate null checks.
- * Convenience method for checking whether an attribute value has changed.
- */
- public boolean valuesAreDifferent(Object value1, Object value2) {
- return ! this.valuesAreEqual(value1, value2);
- }
-
- /**
- * Add a property change listener that is registered for all properties.
- */
- public void addPropertyChangeListener(PropertyChangeListener listener) {
- this.addListener(PROPERTY_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Add a property change listener for the specified property. The listener
- * will be notified only for changes to the specified property.
- */
- public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- this.addListener(propertyName, PROPERTY_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a property change listener that was registered for all properties.
- */
- public void removePropertyChangeListener(PropertyChangeListener listener) {
- this.removeListener(PROPERTY_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a property change listener that was registered for a specific property.
- */
- public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- this.removeListener(propertyName, PROPERTY_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Return whether there are any property change listeners that will
- * be notified when the specified property has changed.
- */
- public boolean hasAnyPropertyChangeListeners(String propertyName) {
- return this.hasAnyListeners(PROPERTY_CHANGE_LISTENER_CLASS, propertyName);
- }
-
- /**
- * Return whether there are any property change listeners that will
- * be notified when any property has changed.
- */
- public boolean hasAnyPropertyChangeListeners() {
- return this.hasAnyListeners(PROPERTY_CHANGE_LISTENER_CLASS);
- }
-
- private PropertyChangeListener[] propertyChangeListeners() {
- return (PropertyChangeListener[]) this.listeners(PROPERTY_CHANGE_LISTENER_CLASS);
- }
-
- /**
- * Fire the specified property change event to any registered listeners.
- * No event is fired if the given event's old and new values are the same;
- * this includes when both values are null. Use a state change event
- * for general purpose notification of changes.
- */
- public void firePropertyChanged(PropertyChangeEvent event) {
- if (this.valuesAreEqual(event.getOldValue(), event.getNewValue())) {
- return;
- }
-
- String propertyName = event.getPropertyName();
-
- PropertyChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- PropertyChangeListener[] propertyChangeListeners = this.propertyChangeListeners();
- if (propertyChangeListeners != null) {
- targets = propertyChangeListeners.clone();
- }
- child = this.child(propertyName);
- }
-
- if (targets != null) {
- for (PropertyChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.propertyChangeListeners(), target);
- }
- if (stillListening) {
- target.propertyChanged(event);
- }
- }
- }
- if (child != null) {
- child.firePropertyChanged(event);
- }
-
- this.sourceChanged(propertyName);
- }
-
- /**
- * Report a bound property update to any registered property change listeners.
- * No event is fired if the given old and new values are the same;
- * this includes when both values are null. Use a state change event
- * for general purpose notification of changes.
- */
- public void firePropertyChanged(String propertyName, Object oldValue, Object newValue) {
-// this.firePropertyChanged(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
- if (this.valuesAreEqual(oldValue, newValue)) {
- return;
- }
-
- PropertyChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- PropertyChangeListener[] propertyChangeListeners = this.propertyChangeListeners();
- if (propertyChangeListeners != null) {
- targets = propertyChangeListeners.clone();
- }
- child = this.child(propertyName);
- }
-
- PropertyChangeEvent event = null;
-
- if (targets != null) {
- for (PropertyChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.propertyChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new PropertyChangeEvent(this.source, propertyName, oldValue, newValue);
- }
- target.propertyChanged(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.firePropertyChanged(propertyName, oldValue, newValue);
- } else {
- child.firePropertyChanged(event);
- }
- }
-
- this.sourceChanged(propertyName);
- }
-
- /**
- * Report an int bound property update to any registered listeners.
- * No event is fired if old and new are equal.
- * <p>
- * This is merely a convenience wrapper around the more general
- * firePropertyChange method that takes Object values.
- */
- public void firePropertyChanged(String propertyName, int oldValue, int newValue) {
-// this.firePropertyChanged(propertyName, new Integer(oldValue), new Integer(newValue));
- if (oldValue == newValue) {
- return;
- }
-
- PropertyChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- PropertyChangeListener[] propertyChangeListeners = this.propertyChangeListeners();
- if (propertyChangeListeners != null) {
- targets = propertyChangeListeners.clone();
- }
- child = this.child(propertyName);
- }
-
- PropertyChangeEvent event = null;
-
- if (targets != null) {
- for (PropertyChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.propertyChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new PropertyChangeEvent(this.source, propertyName, new Integer(oldValue), new Integer(newValue));
- }
- target.propertyChanged(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.firePropertyChanged(propertyName, oldValue, newValue);
- } else {
- child.firePropertyChanged(event);
- }
- }
-
- this.sourceChanged(propertyName);
- }
-
- /**
- * Report a boolean bound property update to any registered listeners.
- * No event is fired if old and new are equal.
- * <p>
- * This is merely a convenience wrapper around the more general
- * firePropertyChange method that takes Object values.
- */
- public void firePropertyChanged(String propertyName, boolean oldValue, boolean newValue) {
-// this.firePropertyChanged(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
- if (oldValue == newValue) {
- return;
- }
-
- PropertyChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- PropertyChangeListener[] propertyChangeListeners = this.propertyChangeListeners();
- if (propertyChangeListeners != null) {
- targets = propertyChangeListeners.clone();
- }
- child = this.child(propertyName);
- }
-
- PropertyChangeEvent event = null;
-
- if (targets != null) {
- for (PropertyChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.propertyChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new PropertyChangeEvent(this.source, propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
- }
- target.propertyChanged(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.firePropertyChanged(propertyName, oldValue, newValue);
- } else {
- child.firePropertyChanged(event);
- }
- }
-
- this.sourceChanged(propertyName);
- }
-
-
- // ********** collection change support **********
-
- protected static final Class<CollectionChangeListener> COLLECTION_CHANGE_LISTENER_CLASS = CollectionChangeListener.class;
-
- /**
- * Add a collection change listener that is registered for all collections.
- */
- public void addCollectionChangeListener(CollectionChangeListener listener) {
- this.addListener(COLLECTION_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Add a collection change listener for the specified collection. The listener
- * will be notified only for changes to the specified collection.
- */
- public void addCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- this.addListener(collectionName, COLLECTION_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a collection change listener that was registered for all collections.
- */
- public void removeCollectionChangeListener(CollectionChangeListener listener) {
- this.removeListener(COLLECTION_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a collection change listener that was registered for a specific collection.
- */
- public void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- this.removeListener(collectionName, COLLECTION_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Return whether there are any collection change listeners that will
- * be notified when the specified collection has changed.
- */
- public boolean hasAnyCollectionChangeListeners(String collectionName) {
- return this.hasAnyListeners(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- }
-
- /**
- * Return whether there are any collection change listeners that will
- * be notified when any collection has changed.
- */
- public boolean hasAnyCollectionChangeListeners() {
- return this.hasAnyListeners(COLLECTION_CHANGE_LISTENER_CLASS);
- }
-
- private CollectionChangeListener[] collectionChangeListeners() {
- return (CollectionChangeListener[]) this.listeners(COLLECTION_CHANGE_LISTENER_CLASS);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireItemsAdded(CollectionChangeEvent event) {
- if (event.itemsSize() == 0) {
- return;
- }
-
- String collectionName = event.getCollectionName();
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- target.itemsAdded(event);
- }
- }
- }
- if (child != null) {
- child.fireItemsAdded(event);
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireItemsAdded(String collectionName, Collection<?> addedItems) {
-// this.fireItemsAdded(new CollectionChangeEvent(this.source, collectionName, addedItems));
- if (addedItems.size() == 0) {
- return;
- }
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- CollectionChangeEvent event = null;
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new CollectionChangeEvent(this.source, collectionName, addedItems);
- }
- target.itemsAdded(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemsAdded(collectionName, addedItems);
- } else {
- child.fireItemsAdded(event);
- }
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireItemAdded(String collectionName, Object addedItem) {
-// this.fireItemsAdded(collectionName, Collections.singleton(addedItem));
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- CollectionChangeEvent event = null;
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new CollectionChangeEvent(this.source, collectionName, Collections.singleton(addedItem));
- }
- target.itemsAdded(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemAdded(collectionName, addedItem);
- } else {
- child.fireItemsAdded(event);
- }
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireItemsRemoved(CollectionChangeEvent event) {
- if (event.itemsSize() == 0) {
- return;
- }
-
- String collectionName = event.getCollectionName();
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- target.itemsRemoved(event);
- }
- }
- }
- if (child != null) {
- child.fireItemsRemoved(event);
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireItemsRemoved(String collectionName, Collection<?> removedItems) {
-// this.fireItemsRemoved(new CollectionChangeEvent(this.source, collectionName, removedItems));
- if (removedItems.size() == 0) {
- return;
- }
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- CollectionChangeEvent event = null;
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new CollectionChangeEvent(this.source, collectionName, removedItems);
- }
- target.itemsRemoved(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemsRemoved(collectionName, removedItems);
- } else {
- child.fireItemsRemoved(event);
- }
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireItemRemoved(String collectionName, Object removedItem) {
-// this.fireItemsRemoved(collectionName, Collections.singleton(removedItem));
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- CollectionChangeEvent event = null;
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new CollectionChangeEvent(this.source, collectionName, Collections.singleton(removedItem));
- }
- target.itemsRemoved(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemRemoved(collectionName, removedItem);
- } else {
- child.fireItemsRemoved(event);
- }
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireCollectionCleared(CollectionChangeEvent event) {
- String collectionName = event.getCollectionName();
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- target.collectionCleared(event);
- }
- }
- }
- if (child != null) {
- child.fireCollectionCleared(event);
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireCollectionCleared(String collectionName) {
-// this.fireCollectionCleared(new CollectionChangeEvent(this.source, collectionName));
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- CollectionChangeEvent event = null;
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new CollectionChangeEvent(this.source, collectionName);
- }
- target.collectionCleared(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireCollectionCleared(collectionName);
- } else {
- child.fireCollectionCleared(event);
- }
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireCollectionChanged(CollectionChangeEvent event) {
- String collectionName = event.getCollectionName();
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- target.collectionChanged(event);
- }
- }
- }
- if (child != null) {
- child.fireCollectionChanged(event);
- }
-
- this.sourceChanged(collectionName);
- }
-
- /**
- * Report a bound collection update to any registered listeners.
- */
- public void fireCollectionChanged(String collectionName) {
-// this.fireCollectionChanged(new CollectionChangeEvent(this.source, collectionName));
-
- CollectionChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- CollectionChangeListener[] collectionChangeListeners = this.collectionChangeListeners();
- if (collectionChangeListeners != null) {
- targets = collectionChangeListeners.clone();
- }
- child = this.child(collectionName);
- }
-
- CollectionChangeEvent event = null;
-
- if (targets != null) {
- for (CollectionChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.collectionChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new CollectionChangeEvent(this.source, collectionName);
- }
- target.collectionChanged(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireCollectionChanged(collectionName);
- } else {
- child.fireCollectionChanged(event);
- }
- }
-
- this.sourceChanged(collectionName);
- }
-
-
- // ********** list change support **********
-
- protected static final Class<ListChangeListener> LIST_CHANGE_LISTENER_CLASS = ListChangeListener.class;
-
- /**
- * Add a list change listener that is registered for all lists.
- */
- public void addListChangeListener(ListChangeListener listener) {
- this.addListener(LIST_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Add a list change listener for the specified list. The listener
- * will be notified only for changes to the specified list.
- */
- public void addListChangeListener(String listName, ListChangeListener listener) {
- this.addListener(listName, LIST_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a list change listener that was registered for all lists.
- */
- public void removeListChangeListener(ListChangeListener listener) {
- this.removeListener(LIST_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a list change listener that was registered for a specific list.
- */
- public void removeListChangeListener(String listName, ListChangeListener listener) {
- this.removeListener(listName, LIST_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Return whether there are any list change listeners that will
- * be notified when the specified list has changed.
- */
- public boolean hasAnyListChangeListeners(String listName) {
- return this.hasAnyListeners(LIST_CHANGE_LISTENER_CLASS, listName);
- }
-
- /**
- * Return whether there are any list change listeners that will
- * be notified when any list has changed.
- */
- public boolean hasAnyListChangeListeners() {
- return this.hasAnyListeners(LIST_CHANGE_LISTENER_CLASS);
- }
-
- private ListChangeListener[] listChangeListeners() {
- return (ListChangeListener[]) this.listeners(LIST_CHANGE_LISTENER_CLASS);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsAdded(ListChangeEvent event) {
- if (event.itemsSize() == 0) {
- return;
- }
-
- String listName = event.getListName();
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- target.itemsAdded(event);
- }
- }
- }
- if (child != null) {
- child.fireItemsAdded(event);
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsAdded(String listName, int index, List<?> addedItems) {
-// this.fireItemsAdded(new ListChangeEvent(this.source, listName, index, addedItems));
- if (addedItems.size() == 0) {
- return;
- }
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, index, addedItems);
- }
- target.itemsAdded(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemsAdded(listName, index, addedItems);
- } else {
- child.fireItemsAdded(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemAdded(String listName, int index, Object addedItem) {
-// this.fireItemsAdded(listName, index, Collections.singletonList(addedItem));
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, index, Collections.singletonList(addedItem));
- }
- target.itemsAdded(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemAdded(listName, index, addedItem);
- } else {
- child.fireItemsAdded(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsRemoved(ListChangeEvent event) {
- if (event.itemsSize() == 0) {
- return;
- }
-
- String listName = event.getListName();
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- target.itemsRemoved(event);
- }
- }
- }
- if (child != null) {
- child.fireItemsRemoved(event);
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsRemoved(String listName, int index, List<?> removedItems) {
-// this.fireItemsRemoved(new ListChangeEvent(this.source, listName, index, removedItems));
- if (removedItems.size() == 0) {
- return;
- }
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, index, removedItems);
- }
- target.itemsRemoved(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemsRemoved(listName, index, removedItems);
- } else {
- child.fireItemsRemoved(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemRemoved(String listName, int index, Object removedItem) {
-// this.fireItemsRemoved(listName, index, Collections.singletonList(removedItem));
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, index, Collections.singletonList(removedItem));
- }
- target.itemsRemoved(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemRemoved(listName, index, removedItem);
- } else {
- child.fireItemsRemoved(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsReplaced(ListChangeEvent event) {
- if (event.itemsSize() == 0) {
- return;
- }
-
- String listName = event.getListName();
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- target.itemsReplaced(event);
- }
- }
- }
- if (child != null) {
- child.fireItemsReplaced(event);
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsReplaced(String listName, int index, List<?> newItems, List<?> replacedItems) {
-// this.fireItemsReplaced(new ListChangeEvent(this.source, listName, index, newItems, replacedItems));
- if (newItems.size() == 0) {
- return;
- }
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, index, newItems, replacedItems);
- }
- target.itemsReplaced(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemsReplaced(listName, index, newItems, replacedItems);
- } else {
- child.fireItemsReplaced(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemReplaced(String listName, int index, Object newItem, Object replacedItem) {
-// this.fireItemsReplaced(listName, index, Collections.singletonList(newItem), Collections.singletonList(replacedItem));
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, index, Collections.singletonList(newItem), Collections.singletonList(replacedItem));
- }
- target.itemsReplaced(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemReplaced(listName, index, newItem, replacedItem);
- } else {
- child.fireItemsReplaced(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsMoved(ListChangeEvent event) {
- if (event.getTargetIndex() == event.getSourceIndex()) {
- return;
- }
-
- String listName = event.getListName();
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- target.itemsMoved(event);
- }
- }
- }
- if (child != null) {
- child.fireItemsMoved(event);
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemsMoved(String listName, int targetIndex, int sourceIndex, int length) {
-// this.fireItemsMoved(new ListChangeEvent(this.source, listName, targetIndex, sourceIndex, length));
- if (targetIndex == sourceIndex) {
- return;
- }
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName, targetIndex, sourceIndex, length);
- }
- target.itemsMoved(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireItemsMoved(listName, targetIndex, sourceIndex, length);
- } else {
- child.fireItemsMoved(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireItemMoved(String listName, int targetIndex, int sourceIndex) {
- this.fireItemsMoved(listName, targetIndex, sourceIndex, 1);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireListCleared(ListChangeEvent event) {
- String listName = event.getListName();
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- target.listCleared(event);
- }
- }
- }
- if (child != null) {
- child.fireListCleared(event);
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireListCleared(String listName) {
-// this.fireListCleared(new ListChangeEvent(this.source, listName));
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName);
- }
- target.listCleared(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireListCleared(listName);
- } else {
- child.fireListCleared(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireListChanged(ListChangeEvent event) {
- String listName = event.getListName();
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- target.listChanged(event);
- }
- }
- }
- if (child != null) {
- child.fireListChanged(event);
- }
-
- this.sourceChanged(listName);
- }
-
- /**
- * Report a bound list update to any registered listeners.
- */
- public void fireListChanged(String listName) {
-// this.fireListChanged(new ListChangeEvent(this.source, listName));
-
- ListChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- ListChangeListener[] listChangeListeners = this.listChangeListeners();
- if (listChangeListeners != null) {
- targets = listChangeListeners.clone();
- }
- child = this.child(listName);
- }
-
- ListChangeEvent event = null;
-
- if (targets != null) {
- for (ListChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.listChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new ListChangeEvent(this.source, listName);
- }
- target.listChanged(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireListChanged(listName);
- } else {
- child.fireListChanged(event);
- }
- }
-
- this.sourceChanged(listName);
- }
-
-
- // ********** tree change support **********
-
- protected static final Class<TreeChangeListener> TREE_CHANGE_LISTENER_CLASS = TreeChangeListener.class;
- private static final Object[] EMPTY_TREE_PATH = new Object[0];
-
- /**
- * Add a tree change listener that is registered for all trees.
- */
- public void addTreeChangeListener(TreeChangeListener listener) {
- this.addListener(TREE_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Add a tree change listener for the specified tree. The listener
- * will be notified only for changes to the specified tree.
- */
- public void addTreeChangeListener(String treeName, TreeChangeListener listener) {
- this.addListener(treeName, TREE_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a tree change listener that was registered for all tree.
- */
- public void removeTreeChangeListener(TreeChangeListener listener) {
- this.removeListener(TREE_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Remove a tree change listener that was registered for a specific tree.
- */
- public void removeTreeChangeListener(String treeName, TreeChangeListener listener) {
- this.removeListener(treeName, TREE_CHANGE_LISTENER_CLASS, listener);
- }
-
- /**
- * Return whether there are any tree change listeners that will
- * be notified when the specified tree has changed.
- */
- public boolean hasAnyTreeChangeListeners(String treeName) {
- return this.hasAnyListeners(TREE_CHANGE_LISTENER_CLASS, treeName);
- }
-
- /**
- * Return whether there are any tree change listeners that will
- * be notified when any tree has changed.
- */
- public boolean hasAnyTreeChangeListeners() {
- return this.hasAnyListeners(TREE_CHANGE_LISTENER_CLASS);
- }
-
- private TreeChangeListener[] treeChangeListeners() {
- return (TreeChangeListener[]) this.listeners(TREE_CHANGE_LISTENER_CLASS);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireNodeAdded(TreeChangeEvent event) {
- String treeName = event.getTreeName();
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- target.nodeAdded(event);
- }
- }
- }
- if (child != null) {
- child.fireNodeAdded(event);
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireNodeAdded(String treeName, Object[] path) {
-// this.fireNodeAdded(new TreeChangeEvent(this.source, treeName, path));
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- TreeChangeEvent event = null;
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new TreeChangeEvent(this.source, treeName, path);
- }
- target.nodeAdded(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireNodeAdded(treeName, path);
- } else {
- child.fireNodeAdded(event);
- }
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireNodeRemoved(TreeChangeEvent event) {
- String treeName = event.getTreeName();
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- target.nodeRemoved(event);
- }
- }
- }
- if (child != null) {
- child.fireNodeRemoved(event);
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireNodeRemoved(String treeName, Object[] path) {
-// this.fireNodeRemoved(new TreeChangeEvent(this.source, treeName, path));
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- TreeChangeEvent event = null;
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new TreeChangeEvent(this.source, treeName, path);
- }
- target.nodeRemoved(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireNodeRemoved(treeName, path);
- } else {
- child.fireNodeRemoved(event);
- }
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireTreeCleared(TreeChangeEvent event) {
- String treeName = event.getTreeName();
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- target.treeCleared(event);
- }
- }
- }
- if (child != null) {
- child.fireTreeCleared(event);
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireTreeCleared(String treeName, Object[] path) {
-// this.fireTreeCleared(new TreeChangeEvent(this.source, treeName, path));
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- TreeChangeEvent event = null;
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new TreeChangeEvent(this.source, treeName, path);
- }
- target.treeCleared(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireTreeCleared(treeName, path);
- } else {
- child.fireTreeCleared(event);
- }
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireTreeCleared(String treeName) {
- this.fireTreeCleared(treeName, EMPTY_TREE_PATH);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireTreeChanged(TreeChangeEvent event) {
- String treeName = event.getTreeName();
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- target.treeChanged(event);
- }
- }
- }
- if (child != null) {
- child.fireTreeChanged(event);
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireTreeChanged(String treeName, Object[] path) {
-// this.fireTreeChanged(new TreeChangeEvent(this.source, treeName, path));
-
- TreeChangeListener[] targets = null;
- ChangeSupport child = null;
-
- synchronized (this) {
- TreeChangeListener[] treeChangeListeners = this.treeChangeListeners();
- if (treeChangeListeners != null) {
- targets = treeChangeListeners.clone();
- }
- child = this.child(treeName);
- }
-
- TreeChangeEvent event = null;
-
- if (targets != null) {
- for (TreeChangeListener target : targets) {
- boolean stillListening;
- synchronized (this) {
- stillListening = CollectionTools.contains(this.treeChangeListeners(), target);
- }
- if (stillListening) {
- if (event == null) {
- // here's the reason for the duplicate code...
- event = new TreeChangeEvent(this.source, treeName, path);
- }
- target.treeChanged(event);
- }
- }
- }
- if (child != null) {
- if (event == null) {
- child.fireTreeChanged(treeName, path);
- } else {
- child.fireTreeChanged(event);
- }
- }
-
- this.sourceChanged(treeName);
- }
-
- /**
- * Report a bound tree update to any registered listeners.
- */
- public void fireTreeChanged(String treeName) {
- this.fireTreeChanged(treeName, EMPTY_TREE_PATH);
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.source);
- }
-
-
- // ********** serialization **********
-
- private synchronized void writeObject(ObjectOutputStream s) throws IOException {
- // write out the source, children, and any hidden stuff
- s.defaultWriteObject();
-
- // only write out Serializable listeners
- int len = this.genericListeners.length;
- for (int i = 0; i < len; i++) {
- this.writeObject(s, this.genericListeners[i]);
- }
- s.writeObject(null);
- }
-
- private void writeObject(ObjectOutputStream s, GenericListenerList gll) throws IOException {
- boolean first = true;
- int len = gll.listeners.length;
- for (int i = 0; i < len; i++) {
- ChangeListener listener = gll.listeners[i];
- if (listener instanceof Serializable) {
- if (first) {
- first = false;
- s.writeObject(gll.listenerClass);
- }
- s.writeObject(listener);
- }
- }
- if ( ! first) {
- s.writeObject(null);
- }
- }
-
- private synchronized void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
- // read in the source, children, and any hidden stuff
- s.defaultReadObject();
-
- // read in generic listener lists
- this.genericListeners = EMPTY_GENERIC_LISTENERS;
- Object o;
- while (null != (o = s.readObject())) {
- @SuppressWarnings("unchecked")
- Class<? extends ChangeListener> listenerClass = (Class<? extends ChangeListener>) o;
- GenericListenerList gll = null;
- while (null != (o = s.readObject())) {
- if (gll == null) {
- gll = this.addGenericListenerList_(listenerClass, (ChangeListener) o);
- } else {
- gll.addListener((ChangeListener) o);
- }
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private <T extends ChangeListener> GenericListenerList addGenericListenerList_(Class<T> listenerClass, ChangeListener listener) {
- return this.addGenericListenerList(listenerClass, (T) listener);
- }
-
-
- // ********** member classes **********
-
- /**
- * Pair a listener class with its "generic" listeners.
- */
- private static class GenericListenerList {
- final Class<? extends ChangeListener> listenerClass;
- ChangeListener[] listeners;
-
- <T extends ChangeListener> GenericListenerList(Class<T> listenerClass, T listener) {
- super();
- this.listenerClass = listenerClass;
- this.listeners = (ChangeListener[]) Array.newInstance(listenerClass, 1);
- this.listeners[0] = listener;
- }
-
- void addListener(ChangeListener listener) {
- this.listeners = CollectionTools.add(this.listeners, listener);
- }
-
- boolean removeListener(ChangeListener listener) {
- int len = this.listeners.length;
- if (len == 0) {
- return false;
- }
- try {
- this.listeners = CollectionTools.remove(this.listeners, listener);
- } catch (ArrayIndexOutOfBoundsException ex) {
- return false; // listener not in the list
- }
- return (this.listeners.length + 1) == len;
- }
-
- boolean hasListeners() {
- return this.listeners.length > 0;
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, ClassTools.shortNameFor(this.listenerClass));
- }
-
- }
-
- /**
- * Pair an aspect name with the change support holding its associated
- * listeners.
- */
- private static class AspectChild implements Serializable {
- final String aspectName;
- final ChangeSupport child;
- private static final long serialVersionUID = 1L;
-
- AspectChild(String aspectName, ChangeSupport child) {
- super();
- this.aspectName = aspectName;
- this.child = child;
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.aspectName);
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/SingleAspectChangeSupport.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/SingleAspectChangeSupport.java
deleted file mode 100644
index 29852e2a0f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/SingleAspectChangeSupport.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model;
-
-import java.util.Collection;
-import java.util.List;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-
-/**
- * This change support class changes the behavior of the standard
- * ChangeSupport in several ways:
- * - All events fired by the source must specify the single aspect.
- * - Listeners are required to be either "generic" listeners or
- * listeners of the single aspect.
- */
-public class SingleAspectChangeSupport
- extends ChangeSupport
-{
- protected final Class<? extends ChangeListener> listenerClass;
- protected final String aspectName;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructor **********
-
- public SingleAspectChangeSupport(Model source, Class<? extends ChangeListener> listenerClass, String aspectName) {
- super(source);
- this.listenerClass = listenerClass;
- this.aspectName = aspectName;
- }
-
-
- // ********** internal behavior **********
-
- private UnsupportedOperationException unsupportedOperationException() {
- return new UnsupportedOperationException("This Model supports only changes for the listener type \"" + this.listenerClass.getName()
- + "\" and the aspect \"" + this.aspectName + "\"");
- }
-
- private void check(Class<? extends ChangeListener> lClass, String aName) {
- if (lClass != this.listenerClass) {
- throw new IllegalArgumentException("This Model supports only changes for the listener type \"" + this.listenerClass.getName() + "\" : \"" + lClass.getName() + "\"");
- }
- if (aName != this.aspectName) {
- throw new IllegalArgumentException("This Model supports only changes for the aspect \"" + this.aspectName + "\" : \"" + aName + "\"");
- }
- }
-
- @Override
- protected <T extends ChangeListener> void addListener(String aName, Class<T> lClass, T listener) {
- this.check(lClass, aName);
- super.addListener(aName, lClass, listener);
- }
-
- @Override
- protected <T extends ChangeListener> void removeListener(String aName, Class<T> lClass, T listener) {
- this.check(lClass, aName);
- super.removeListener(aName, lClass, listener);
- }
-
-
- // ********** internal queries **********
-
- @Override
- protected boolean hasAnyListeners(Class<? extends ChangeListener> lClass, String aName) {
- this.check(lClass, aName);
- return super.hasAnyListeners(lClass, aName);
- }
-
-
- // ********** state change support **********
-
- @Override
- public void fireStateChanged(StateChangeEvent event) {
- throw this.unsupportedOperationException();
- }
-
- @Override
- public void fireStateChanged() {
- throw this.unsupportedOperationException();
- }
-
-
- // ********** property change support **********
-
- @Override
- public void firePropertyChanged(PropertyChangeEvent event) {
- this.check(PROPERTY_CHANGE_LISTENER_CLASS, event.getPropertyName());
- super.firePropertyChanged(event);
- }
-
- @Override
- public void firePropertyChanged(String propertyName, Object oldValue, Object newValue) {
- this.check(PROPERTY_CHANGE_LISTENER_CLASS, propertyName);
- super.firePropertyChanged(propertyName, oldValue, newValue);
- }
-
- @Override
- public void firePropertyChanged(String propertyName, int oldValue, int newValue) {
- this.check(PROPERTY_CHANGE_LISTENER_CLASS, propertyName);
- super.firePropertyChanged(propertyName, oldValue, newValue);
- }
-
- @Override
- public void firePropertyChanged(String propertyName, boolean oldValue, boolean newValue) {
- this.check(PROPERTY_CHANGE_LISTENER_CLASS, propertyName);
- super.firePropertyChanged(propertyName, oldValue, newValue);
- }
-
-
- // ********** collection change support **********
-
- @Override
- public void fireItemsAdded(CollectionChangeEvent event) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, event.getCollectionName());
- super.fireItemsAdded(event);
- }
-
- @Override
- public void fireItemsAdded(String collectionName, Collection<?> addedItems) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- super.fireItemsAdded(collectionName, addedItems);
- }
-
- @Override
- public void fireItemAdded(String collectionName, Object addedItem) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- super.fireItemAdded(collectionName, addedItem);
- }
-
- @Override
- public void fireItemsRemoved(CollectionChangeEvent event) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, event.getCollectionName());
- super.fireItemsRemoved(event);
- }
-
- @Override
- public void fireItemsRemoved(String collectionName, Collection<?> removedItems) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- super.fireItemsRemoved(collectionName, removedItems);
- }
-
- @Override
- public void fireItemRemoved(String collectionName, Object removedItem) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- super.fireItemRemoved(collectionName, removedItem);
- }
-
- @Override
- public void fireCollectionCleared(CollectionChangeEvent event) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, event.getCollectionName());
- super.fireCollectionCleared(event);
- }
-
- @Override
- public void fireCollectionCleared(String collectionName) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- super.fireCollectionCleared(collectionName);
- }
-
- @Override
- public void fireCollectionChanged(CollectionChangeEvent event) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, event.getCollectionName());
- super.fireCollectionChanged(event);
- }
-
- @Override
- public void fireCollectionChanged(String collectionName) {
- this.check(COLLECTION_CHANGE_LISTENER_CLASS, collectionName);
- super.fireCollectionChanged(collectionName);
- }
-
-
- // ********** list change support **********
-
- @Override
- public void fireItemsAdded(ListChangeEvent event) {
- this.check(LIST_CHANGE_LISTENER_CLASS, event.getListName());
- super.fireItemsAdded(event);
- }
-
- @Override
- public void fireItemsAdded(String listName, int index, List<?> addedItems) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemsAdded(listName, index, addedItems);
- }
-
- @Override
- public void fireItemAdded(String listName, int index, Object addedItem) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemAdded(listName, index, addedItem);
- }
-
- @Override
- public void fireItemsRemoved(ListChangeEvent event) {
- this.check(LIST_CHANGE_LISTENER_CLASS, event.getListName());
- super.fireItemsRemoved(event);
- }
-
- @Override
- public void fireItemsRemoved(String listName, int index, List<?> removedItems) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemsRemoved(listName, index, removedItems);
- }
-
- @Override
- public void fireItemRemoved(String listName, int index, Object removedItem) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemRemoved(listName, index, removedItem);
- }
-
- @Override
- public void fireItemsReplaced(ListChangeEvent event) {
- this.check(LIST_CHANGE_LISTENER_CLASS, event.getListName());
- super.fireItemsReplaced(event);
- }
-
- @Override
- public void fireItemsReplaced(String listName, int index, List<?> newItems, List<?> replacedItems) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemsReplaced(listName, index, newItems, replacedItems);
- }
-
- @Override
- public void fireItemReplaced(String listName, int index, Object newItem, Object replacedItem) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemReplaced(listName, index, newItem, replacedItem);
- }
-
- @Override
- public void fireItemsMoved(ListChangeEvent event) {
- this.check(LIST_CHANGE_LISTENER_CLASS, event.getListName());
- super.fireItemsMoved(event);
- }
-
- @Override
- public void fireItemsMoved(String listName, int targetIndex, int sourceIndex, int length) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireItemsMoved(listName, targetIndex, sourceIndex, length);
- }
-
- @Override
- public void fireListCleared(ListChangeEvent event) {
- this.check(LIST_CHANGE_LISTENER_CLASS, event.getListName());
- super.fireListCleared(event);
- }
-
- @Override
- public void fireListCleared(String listName) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireListCleared(listName);
- }
-
- @Override
- public void fireListChanged(ListChangeEvent event) {
- this.check(LIST_CHANGE_LISTENER_CLASS, event.getListName());
- super.fireListChanged(event);
- }
-
- @Override
- public void fireListChanged(String listName) {
- this.check(LIST_CHANGE_LISTENER_CLASS, listName);
- super.fireListChanged(listName);
- }
-
-
- // ********** tree change support **********
-
- @Override
- public void fireNodeAdded(TreeChangeEvent event) {
- this.check(TREE_CHANGE_LISTENER_CLASS, event.getTreeName());
- super.fireNodeAdded(event);
- }
-
- @Override
- public void fireNodeAdded(String treeName, Object[] path) {
- this.check(TREE_CHANGE_LISTENER_CLASS, treeName);
- super.fireNodeAdded(treeName, path);
- }
-
- @Override
- public void fireNodeRemoved(TreeChangeEvent event) {
- this.check(TREE_CHANGE_LISTENER_CLASS, event.getTreeName());
- super.fireNodeRemoved(event);
- }
-
- @Override
- public void fireNodeRemoved(String treeName, Object[] path) {
- this.check(TREE_CHANGE_LISTENER_CLASS, treeName);
- super.fireNodeRemoved(treeName, path);
- }
-
- @Override
- public void fireTreeCleared(TreeChangeEvent event) {
- this.check(TREE_CHANGE_LISTENER_CLASS, event.getTreeName());
- super.fireTreeCleared(event);
- }
-
- @Override
- public void fireTreeCleared(String treeName, Object[] path) {
- this.check(TREE_CHANGE_LISTENER_CLASS, treeName);
- super.fireTreeCleared(treeName, path);
- }
-
- @Override
- public void fireTreeChanged(TreeChangeEvent event) {
- this.check(TREE_CHANGE_LISTENER_CLASS, event.getTreeName());
- super.fireTreeChanged(event);
- }
-
- @Override
- public void fireTreeChanged(String treeName, Object[] path) {
- this.check(TREE_CHANGE_LISTENER_CLASS, treeName);
- super.fireTreeChanged(treeName, path);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTCollectionChangeListenerWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTCollectionChangeListenerWrapper.java
deleted file mode 100644
index 4cab405723..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTCollectionChangeListenerWrapper.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.listener.awt;
-
-import java.awt.EventQueue;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-
-/**
- * Wrap another collection change listener and forward events to it on the AWT
- * event queue.
- */
-public class AWTCollectionChangeListenerWrapper
- implements CollectionChangeListener
-{
- private final CollectionChangeListener listener;
-
- public AWTCollectionChangeListenerWrapper(CollectionChangeListener listener) {
- super();
- if (listener == null) {
- throw new NullPointerException();
- }
- this.listener = listener;
- }
-
- public void itemsAdded(CollectionChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.itemsAdded_(event);
- } else {
- this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
- }
- }
-
- public void itemsRemoved(CollectionChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.itemsRemoved_(event);
- } else {
- this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
- }
- }
-
- public void collectionCleared(CollectionChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.collectionCleared_(event);
- } else {
- this.executeOnEventQueue(this.buildCollectionClearedRunnable(event));
- }
- }
-
- public void collectionChanged(CollectionChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.collectionChanged_(event);
- } else {
- this.executeOnEventQueue(this.buildCollectionChangedRunnable(event));
- }
- }
-
- private Runnable buildItemsAddedRunnable(final CollectionChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTCollectionChangeListenerWrapper.this.itemsAdded_(event);
- }
- @Override
- public String toString() {
- return "items added";
- }
- };
- }
-
- private Runnable buildItemsRemovedRunnable(final CollectionChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTCollectionChangeListenerWrapper.this.itemsRemoved_(event);
- }
- @Override
- public String toString() {
- return "items removed";
- }
- };
- }
-
- private Runnable buildCollectionClearedRunnable(final CollectionChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTCollectionChangeListenerWrapper.this.collectionCleared_(event);
- }
- @Override
- public String toString() {
- return "collection cleared";
- }
- };
- }
-
- private Runnable buildCollectionChangedRunnable(final CollectionChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTCollectionChangeListenerWrapper.this.collectionChanged_(event);
- }
- @Override
- public String toString() {
- return "collection changed";
- }
- };
- }
-
- /**
- * EventQueue#invokeLater(Runnable) seems to work OK;
- * but using #invokeAndWait(Runnable) can sometimes make things
- * more predictable when debugging, at the risk of deadlocks.
- */
- private void executeOnEventQueue(Runnable r) {
- EventQueue.invokeLater(r);
-// try {
-// EventQueue.invokeAndWait(r);
-// } catch (InterruptedException ex) {
-// throw new RuntimeException(ex);
-// } catch (java.lang.reflect.InvocationTargetException ex) {
-// throw new RuntimeException(ex);
-// }
- }
-
- void itemsAdded_(CollectionChangeEvent event) {
- this.listener.itemsAdded(event);
- }
-
- void itemsRemoved_(CollectionChangeEvent event) {
- this.listener.itemsRemoved(event);
- }
-
- void collectionCleared_(CollectionChangeEvent event) {
- this.listener.collectionCleared(event);
- }
-
- void collectionChanged_(CollectionChangeEvent event) {
- this.listener.collectionChanged(event);
- }
-
- @Override
- public String toString() {
- return "AWT(" + this.listener.toString() + ")";
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTListChangeListenerWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTListChangeListenerWrapper.java
deleted file mode 100644
index 7bed089ac8..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTListChangeListenerWrapper.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.listener.awt;
-
-import java.awt.EventQueue;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-
-/**
- * Wrap another list change listener and forward events to it on the AWT
- * event queue.
- */
-public class AWTListChangeListenerWrapper
- implements ListChangeListener
-{
- private final ListChangeListener listener;
-
- public AWTListChangeListenerWrapper(ListChangeListener listener) {
- super();
- if (listener == null) {
- throw new NullPointerException();
- }
- this.listener = listener;
- }
-
- public void itemsAdded(ListChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.itemsAdded_(event);
- } else {
- this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
- }
- }
-
- public void itemsRemoved(ListChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.itemsRemoved_(event);
- } else {
- this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
- }
- }
-
- public void itemsMoved(ListChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.itemsMoved_(event);
- } else {
- this.executeOnEventQueue(this.buildItemsMovedRunnable(event));
- }
- }
-
- public void itemsReplaced(ListChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.itemsReplaced_(event);
- } else {
- this.executeOnEventQueue(this.buildItemsReplacedRunnable(event));
- }
- }
-
- public void listCleared(ListChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.listCleared_(event);
- } else {
- this.executeOnEventQueue(this.buildListClearedRunnable(event));
- }
- }
-
- public void listChanged(ListChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.listChanged_(event);
- } else {
- this.executeOnEventQueue(this.buildListChangedRunnable(event));
- }
- }
-
- private Runnable buildItemsAddedRunnable(final ListChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTListChangeListenerWrapper.this.itemsAdded_(event);
- }
- @Override
- public String toString() {
- return "items added";
- }
- };
- }
-
- private Runnable buildItemsRemovedRunnable(final ListChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTListChangeListenerWrapper.this.itemsRemoved_(event);
- }
- @Override
- public String toString() {
- return "items removed";
- }
- };
- }
-
- private Runnable buildItemsMovedRunnable(final ListChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTListChangeListenerWrapper.this.itemsMoved_(event);
- }
- @Override
- public String toString() {
- return "items moved";
- }
- };
- }
-
- private Runnable buildItemsReplacedRunnable(final ListChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTListChangeListenerWrapper.this.itemsReplaced_(event);
- }
- @Override
- public String toString() {
- return "items replaced";
- }
- };
- }
-
- private Runnable buildListClearedRunnable(final ListChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTListChangeListenerWrapper.this.listCleared_(event);
- }
- @Override
- public String toString() {
- return "list cleared";
- }
- };
- }
-
- private Runnable buildListChangedRunnable(final ListChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTListChangeListenerWrapper.this.listChanged_(event);
- }
- @Override
- public String toString() {
- return "list changed";
- }
- };
- }
-
- /**
- * EventQueue#invokeLater(Runnable) seems to work OK;
- * but using #invokeAndWait(Runnable) can sometimes make things
- * more predictable when debugging, at the risk of deadlocks.
- */
- private void executeOnEventQueue(Runnable r) {
- EventQueue.invokeLater(r);
-// try {
-// EventQueue.invokeAndWait(r);
-// } catch (InterruptedException ex) {
-// throw new RuntimeException(ex);
-// } catch (java.lang.reflect.InvocationTargetException ex) {
-// throw new RuntimeException(ex);
-// }
- }
-
- void itemsAdded_(ListChangeEvent event) {
- this.listener.itemsAdded(event);
- }
-
- void itemsRemoved_(ListChangeEvent event) {
- this.listener.itemsRemoved(event);
- }
-
- void itemsMoved_(ListChangeEvent event) {
- this.listener.itemsMoved(event);
- }
-
- void itemsReplaced_(ListChangeEvent event) {
- this.listener.itemsReplaced(event);
- }
-
- void listCleared_(ListChangeEvent event) {
- this.listener.listCleared(event);
- }
-
- void listChanged_(ListChangeEvent event) {
- this.listener.listChanged(event);
- }
-
- @Override
- public String toString() {
- return "AWT(" + this.listener.toString() + ")";
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java
deleted file mode 100644
index bcc372ac02..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.listener.awt;
-
-import java.awt.EventQueue;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-
-/**
- * Wrap another property change listener and forward events to it on the AWT
- * event queue.
- */
-public class AWTPropertyChangeListenerWrapper
- implements PropertyChangeListener
-{
- private final PropertyChangeListener listener;
-
-
- public AWTPropertyChangeListenerWrapper(PropertyChangeListener listener) {
- super();
- if (listener == null) {
- throw new NullPointerException();
- }
- this.listener = listener;
- }
-
- public void propertyChanged(PropertyChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.propertyChanged_(event);
- } else {
- this.executeOnEventQueue(this.buildRunnable(event));
- }
- }
-
- private Runnable buildRunnable(final PropertyChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTPropertyChangeListenerWrapper.this.propertyChanged_(event);
- }
- };
- }
-
- /**
- * EventQueue#invokeLater(Runnable) seems to work OK;
- * but using #invokeAndWait(Runnable) can sometimes make things
- * more predictable when debugging, at the risk of deadlocks.
- */
- private void executeOnEventQueue(Runnable r) {
- EventQueue.invokeLater(r);
-// try {
-// EventQueue.invokeAndWait(r);
-// } catch (InterruptedException ex) {
-// throw new RuntimeException(ex);
-// } catch (java.lang.reflect.InvocationTargetException ex) {
-// throw new RuntimeException(ex);
-// }
- }
-
- void propertyChanged_(PropertyChangeEvent event) {
- this.listener.propertyChanged(event);
- }
-
- @Override
- public String toString() {
- return "AWT(" + this.listener.toString() + ")";
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java
deleted file mode 100644
index f5f2988d04..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.listener.awt;
-
-import java.awt.EventQueue;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-
-/**
- * Wrap another state change listener and forward events to it on the AWT
- * event queue.
- */
-public class AWTStateChangeListenerWrapper
- implements StateChangeListener
-{
- private final StateChangeListener listener;
-
- public AWTStateChangeListenerWrapper(StateChangeListener listener) {
- super();
- if (listener == null) {
- throw new NullPointerException();
- }
- this.listener = listener;
- }
-
- public void stateChanged(StateChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.stateChanged_(event);
- } else {
- this.executeOnEventQueue(this.buildRunnable(event));
- }
- }
-
- private Runnable buildRunnable(final StateChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTStateChangeListenerWrapper.this.stateChanged_(event);
- }
- };
- }
-
- /**
- * EventQueue#invokeLater(Runnable) seems to work OK;
- * but using #invokeAndWait(Runnable) can sometimes make things
- * more predictable when debugging, at the risk of deadlocks.
- */
- private void executeOnEventQueue(Runnable r) {
- EventQueue.invokeLater(r);
-// try {
-// EventQueue.invokeAndWait(r);
-// } catch (InterruptedException ex) {
-// throw new RuntimeException(ex);
-// } catch (java.lang.reflect.InvocationTargetException ex) {
-// throw new RuntimeException(ex);
-// }
- }
-
- void stateChanged_(StateChangeEvent event) {
- this.listener.stateChanged(event);
- }
-
- @Override
- public String toString() {
- return "AWT(" + this.listener.toString() + ")";
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTTreeChangeListenerWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTTreeChangeListenerWrapper.java
deleted file mode 100644
index be7cfb113a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/listener/awt/AWTTreeChangeListenerWrapper.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.listener.awt;
-
-import java.awt.EventQueue;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-
-/**
- * Wrap another tree change listener and forward events to it on the AWT
- * event queue.
- */
-public class AWTTreeChangeListenerWrapper
- implements TreeChangeListener
-{
- private final TreeChangeListener listener;
-
- public AWTTreeChangeListenerWrapper(TreeChangeListener listener) {
- super();
- if (listener == null) {
- throw new NullPointerException();
- }
- this.listener = listener;
- }
-
- public void nodeAdded(TreeChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.nodeAdded_(event);
- } else {
- this.executeOnEventQueue(this.buildNodeAddedRunnable(event));
- }
- }
-
- public void nodeRemoved(TreeChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.nodeRemoved_(event);
- } else {
- this.executeOnEventQueue(this.buildNodeRemovedRunnable(event));
- }
- }
-
- public void treeCleared(TreeChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.treeCleared_(event);
- } else {
- this.executeOnEventQueue(this.buildTreeClearedRunnable(event));
- }
- }
-
- public void treeChanged(TreeChangeEvent event) {
- if (EventQueue.isDispatchThread()) {
- this.treeChanged_(event);
- } else {
- this.executeOnEventQueue(this.buildTreeChangedRunnable(event));
- }
- }
-
- private Runnable buildNodeAddedRunnable(final TreeChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTTreeChangeListenerWrapper.this.nodeAdded_(event);
- }
- @Override
- public String toString() {
- return "node added";
- }
- };
- }
-
- private Runnable buildNodeRemovedRunnable(final TreeChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTTreeChangeListenerWrapper.this.nodeRemoved_(event);
- }
- @Override
- public String toString() {
- return "node removed";
- }
- };
- }
-
- private Runnable buildTreeClearedRunnable(final TreeChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTTreeChangeListenerWrapper.this.treeCleared_(event);
- }
- @Override
- public String toString() {
- return "tree cleared";
- }
- };
- }
-
- private Runnable buildTreeChangedRunnable(final TreeChangeEvent event) {
- return new Runnable() {
- public void run() {
- AWTTreeChangeListenerWrapper.this.treeChanged_(event);
- }
- @Override
- public String toString() {
- return "tree changed";
- }
- };
- }
-
- /**
- * EventQueue#invokeLater(Runnable) seems to work OK;
- * but using #invokeAndWait(Runnable) can sometimes make things
- * more predictable when debugging, at the risk of deadlocks.
- */
- private void executeOnEventQueue(Runnable r) {
- EventQueue.invokeLater(r);
-// try {
-// EventQueue.invokeAndWait(r);
-// } catch (InterruptedException ex) {
-// throw new RuntimeException(ex);
-// } catch (java.lang.reflect.InvocationTargetException ex) {
-// throw new RuntimeException(ex);
-// }
- }
-
- void nodeAdded_(TreeChangeEvent event) {
- this.listener.nodeAdded(event);
- }
-
- void nodeRemoved_(TreeChangeEvent event) {
- this.listener.nodeRemoved(event);
- }
-
- void treeCleared_(TreeChangeEvent event) {
- this.listener.treeCleared(event);
- }
-
- void treeChanged_(TreeChangeEvent event) {
- this.listener.treeChanged(event);
- }
-
- @Override
- public String toString() {
- return "AWT(" + this.listener.toString() + ")";
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java
deleted file mode 100644
index 906c2e147c..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AbstractTreeNodeValueModel.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import java.util.List;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.ChainIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.TreeNodeValueModel;
-
-/**
- * Subclasses need only implement the following methods:
- *
- * #value()
- * return the user-determined "value" of the node,
- * i.e. the object "wrapped" by the node
- *
- * #setValue(Object)
- * set the user-determined "value" of the node,
- * i.e. the object "wrapped" by the node;
- * typically only overridden for nodes with "primitive" values
- *
- * #parent()
- * return the parent of the node, which should be another
- * TreeNodeValueModel
- *
- * #childrenModel()
- * return a ListValueModel for the node's children
- *
- * #engageValue() and #disengageValue()
- * override these methods to listen to the node's value if
- * it can change in a way that should be reflected in the tree
- */
-public abstract class AbstractTreeNodeValueModel<T>
- extends AbstractModel
- implements TreeNodeValueModel<T>
-{
-
-
- // ********** constructors **********
-
- /**
- * Default constructor.
- */
- protected AbstractTreeNodeValueModel() {
- super();
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- // this model fires *both* "value property change" and "state change" events...
-// return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE);
- return super.buildChangeSupport();
- }
-
-
- // ********** extend AbstractModel implementation **********
-
- /**
- * Clients should be adding both "state change" and "value property change"
- * listeners.
- */
- @Override
- public void addStateChangeListener(StateChangeListener listener) {
- if (this.hasNoStateChangeListeners()) {
- this.engageValue();
- }
- super.addStateChangeListener(listener);
- }
-
- /**
- * Begin listening to the node's value's state. If the state of the node changes
- * in a way that should be reflected in the tree, fire a "state change" event.
- */
- protected abstract void engageValue();
-
- /**
- * @see #addStateChangeListener(StateChangeListener)
- */
- @Override
- public void removeStateChangeListener(StateChangeListener listener) {
- super.removeStateChangeListener(listener);
- if (this.hasNoStateChangeListeners()) {
- this.disengageValue();
- }
- }
-
- /**
- * Stop listening to the node's value.
- * @see #engageValue()
- */
- protected abstract void disengageValue();
-
-
- // ********** WritablePropertyValueModel implementation **********
-
- public void setValue(T value) {
- throw new UnsupportedOperationException();
- }
-
-
- // ********** TreeNodeValueModel implementation **********
-
- @SuppressWarnings("unchecked")
- public TreeNodeValueModel<T>[] path() {
- List<TreeNodeValueModel<T>> path = CollectionTools.reverseList(this.backPath());
- return path.toArray(new TreeNodeValueModel[path.size()]);
- }
-
- /**
- * Return an iterator that climbs up the node's path,
- * starting with, and including, the node
- * and up to, and including, the root node.
- */
- protected Iterator<TreeNodeValueModel<T>> backPath() {
- return new ChainIterator<TreeNodeValueModel<T>>(this) {
- @Override
- protected TreeNodeValueModel<T> nextLink(TreeNodeValueModel<T> currentLink) {
- return currentLink.parent();
- }
- };
- }
-
- public TreeNodeValueModel<T> child(int index) {
- return this.childrenModel().get(index);
- }
-
- public int childrenSize() {
- return this.childrenModel().size();
- }
-
- public int indexOfChild(TreeNodeValueModel<T> child) {
- ListValueModel<TreeNodeValueModel<T>> children = this.childrenModel();
- int size = children.size();
- for (int i = 0; i < size; i++) {
- if (children.get(i) == child) {
- return i;
- }
- }
- return -1;
- }
-
- public boolean isLeaf() {
- return this.childrenModel().size() == 0;
- }
-
-
- // ********** standard methods **********
-
- /**
- * We implement #equals(Object) so that TreePaths containing these nodes
- * will resolve properly when the nodes contain the same values. This is
- * necessary because nodes are dropped and rebuilt willy-nilly when dealing
- * with a sorted list of children; and this allows us to save and restore
- * a tree's expanded paths. The nodes in the expanded paths that are
- * saved before any modification (e.g. renaming a node) will be different
- * from the nodes in the tree's paths after the modification, if the modification
- * results in a possible change in the node sort order. ~bjv
- */
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
- if (o.getClass() != this.getClass()) {
- return false;
- }
- @SuppressWarnings("unchecked")
- AbstractTreeNodeValueModel<T> other = (AbstractTreeNodeValueModel<T>) o;
- return this.getValue().equals(other.getValue());
- }
-
- @Override
- public int hashCode() {
- return this.getValue().hashCode();
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.getValue());
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java
deleted file mode 100644
index f7d33d56e3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectAdapter.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This abstract extension of AbstractModel provides a base for adding
- * change listeners (PropertyChange, CollectionChange, ListChange, TreeChange)
- * to a subject and converting the subject's change notifications into a single
- * set of change notifications for a common aspect (e.g. VALUE).
- *
- * The adapter will only listen to the subject (and subject holder) when the
- * adapter itself actually has listeners. This will allow the adapter to be
- * garbage collected when appropriate
- */
-public abstract class AspectAdapter<S>
- extends AbstractModel
-{
- /**
- * The subject that holds the aspect and fires
- * change notification when the aspect changes.
- * We need to hold on to this directly so we can
- * disengage it when it changes.
- */
- protected S subject;
-
- /**
- * A value model that holds the subject
- * that holds the aspect and provides change notification.
- * This is useful when there are a number of AspectAdapters
- * that have the same subject and that subject can change.
- * All the AspectAdapters should share the same subject holder.
- * For now, this is can only be set upon construction and is
- * immutable.
- */
- protected final PropertyValueModel<? extends S> subjectHolder;
-
- /** A listener that keeps us in synch with the subjectHolder. */
- protected final PropertyChangeListener subjectChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an AspectAdapter for the specified subject.
- */
- protected AspectAdapter(S subject) {
- this(new StaticPropertyValueModel<S>(subject));
- }
-
- /**
- * Construct an AspectAdapter for the specified subject holder.
- * The subject holder cannot be null.
- */
- protected AspectAdapter(PropertyValueModel<? extends S> subjectHolder) {
- super();
- if (subjectHolder == null) {
- throw new NullPointerException();
- }
- this.subjectHolder = subjectHolder;
- this.subjectChangeListener = this.buildSubjectChangeListener();
- // the subject is null when we are not listening to it
- // this will typically result in our value being null
- this.subject = null;
- }
-
-
- // ********** initialization **********
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new LocalChangeSupport(this, this.getListenerClass(), this.getListenerAspectName());
- }
-
- /**
- * The subject holder's value has changed, keep our subject in synch.
- */
- protected PropertyChangeListener buildSubjectChangeListener() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- AspectAdapter.this.subjectChanged();
- }
- @Override
- public String toString() {
- return "subject change listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- /**
- * The subject has changed. Notify listeners that the value has changed.
- */
- protected synchronized void subjectChanged() {
- Object oldValue = this.getValue();
- boolean hasListeners = this.hasListeners();
- if (hasListeners) {
- this.disengageSubject();
- }
- this.subject = this.subjectHolder.getValue();
- if (hasListeners) {
- this.engageSubject();
- this.fireAspectChange(oldValue, this.getValue());
- }
- }
-
- /**
- * Return the aspect's current value.
- */
- protected abstract Object getValue();
-
- /**
- * Return the class of listener that is interested in the aspect adapter's
- * changes.
- */
- protected abstract Class<? extends ChangeListener> getListenerClass();
-
- /**
- * Return the name of the aspect adapter's aspect (e.g. VALUE).
- * This is the name of the aspect adapter's single aspect, not the
- * name of the subject's aspect the aspect adapter is adapting.
- */
- protected abstract String getListenerAspectName();
-
- /**
- * Return whether there are any listeners for the aspect.
- */
- protected abstract boolean hasListeners();
-
- /**
- * Return whether there are no listeners for the aspect.
- */
- protected boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
- /**
- * The aspect has changed, notify listeners appropriately.
- */
- protected abstract void fireAspectChange(Object oldValue, Object newValue);
-
- protected void engageSubject() {
- // check for nothing to listen to
- if (this.subject != null) {
- this.engageSubject_();
- }
- }
-
- /**
- * The subject is not null - add our listener.
- */
- protected abstract void engageSubject_();
-
- protected void disengageSubject() {
- // check for nothing to listen to
- if (this.subject != null) {
- this.disengageSubject_();
- }
- }
-
- /**
- * The subject is not null - remove our listener.
- */
- protected abstract void disengageSubject_();
-
- protected void engageSubjectHolder() {
- this.subjectHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.subjectChangeListener);
- // synch our subject *after* we start listening to the subject holder,
- // since its value might change when a listener is added
- this.subject = this.subjectHolder.getValue();
- }
-
- protected void disengageSubjectHolder() {
- this.subjectHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.subjectChangeListener);
- // clear out the subject when we are not listening to its holder
- this.subject = null;
- }
-
- protected void engageModels() {
- this.engageSubjectHolder();
- this.engageSubject();
- }
-
- protected void disengageModels() {
- this.disengageSubject();
- this.disengageSubjectHolder();
- }
-
-
- // ********** local change support **********
-
- /**
- * Extend change support to start listening to the aspect adapter's
- * models (the subject holder and the subject itself) when the first
- * relevant listener is added.
- * Conversely, stop listening to the aspect adapter's models when the
- * last relevant listener is removed.
- * A relevant listener is a listener of the relevant type.
- */
- protected class LocalChangeSupport extends SingleAspectChangeSupport {
- private static final long serialVersionUID = 1L;
-
- public LocalChangeSupport(AspectAdapter<S> source, Class<? extends ChangeListener> listenerClass, String aspectName) {
- super(source, listenerClass, aspectName);
- }
-
- protected boolean listenerIsRelevant(Class<? extends ChangeListener> lClass) {
- return lClass == this.listenerClass;
- }
-
- protected boolean hasNoRelevantListeners(Class<? extends ChangeListener> lClass) {
- return this.listenerIsRelevant(lClass)
- && this.hasNoListeners(lClass);
- }
-
- protected boolean listenerIsRelevant(Class<? extends ChangeListener> lClass, String listenerAspectName) {
- return this.listenerIsRelevant(lClass)
- && (listenerAspectName == AspectAdapter.this.getListenerAspectName());
- }
-
- protected boolean hasNoRelevantListeners(Class<? extends ChangeListener> lClass, String listenerAspectName) {
- return this.listenerIsRelevant(lClass, listenerAspectName)
- && this.hasNoListeners(lClass, listenerAspectName);
- }
-
-
- // ********** overrides **********
-
- @Override
- protected <T extends ChangeListener> void addListener(Class<T> lClass, T listener) {
- if (this.hasNoRelevantListeners(lClass)) {
- AspectAdapter.this.engageModels();
- }
- super.addListener(lClass, listener);
- }
-
- @Override
- protected <T extends ChangeListener> void addListener(String listenerAspectName, Class<T> lClass, T listener) {
- if (this.hasNoRelevantListeners(lClass, listenerAspectName)) {
- AspectAdapter.this.engageModels();
- }
- super.addListener(listenerAspectName, lClass, listener);
- }
-
- @Override
- protected <T extends ChangeListener> void removeListener(Class<T> lClass, T listener) {
- super.removeListener(lClass, listener);
- if (this.hasNoRelevantListeners(lClass)) {
- AspectAdapter.this.disengageModels();
- }
- }
-
- @Override
- protected <T extends ChangeListener> void removeListener(String listenerAspectName, Class<T> lClass, T listener) {
- super.removeListener(listenerAspectName, lClass, listener);
- if (this.hasNoRelevantListeners(lClass, listenerAspectName)) {
- AspectAdapter.this.disengageModels();
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java
deleted file mode 100644
index 75853757ad..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/AspectPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a value model, "lazily" listen to it, and convert
- * its change notifications into property value model change
- * notifications.
- *
- * Subclasses must override:
- * - #buildValue()
- * to return the current property value, as derived from the
- * current model value
- *
- */
-public abstract class AspectPropertyValueModelAdapter<T>
- extends AbstractModel
- implements PropertyValueModel<T>
-{
- /**
- * Cache the current value so we can pass an "old value" when
- * we fire a property change event.
- * We need this because the value may be calculated and we may
- * not able to derive the "old value" from the collection
- * change event fired by the collection value model.
- */
- protected T value;
-
-
- // ********** constructor/initialization **********
-
- protected AspectPropertyValueModelAdapter() {
- super();
- // our value is null when we are not listening to the collection holder
- this.value = null;
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, PropertyChangeListener.class, VALUE);
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- /**
- * Return the cached value.
- */
- public T getValue() {
- return this.value;
- }
-
-
- // ********** extend change support **********
-
- /**
- * Extend to start listening to the wrapped collection if necessary.
- */
- @Override
- public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addPropertyChangeListener(listener);
- }
-
- /**
- * Extend to start listening to the wrapped collection if necessary.
- */
- @Override
- public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- if (propertyName == VALUE && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addPropertyChangeListener(propertyName, listener);
- }
-
- /**
- * Extend to stop listening to the wrapped collection if necessary.
- */
- @Override
- public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
- super.removePropertyChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to stop listening to the wrapped collection if necessary.
- */
- @Override
- public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- super.removePropertyChangeListener(propertyName, listener);
- if (propertyName == VALUE && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether there are any listeners for the aspect.
- */
- protected boolean hasListeners() {
- return this.hasAnyPropertyChangeListeners(VALUE);
- }
-
- /**
- * Return whether there are any listeners for the aspect.
- */
- protected boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the model and build the value.
- */
- protected void engageModel() {
- this.engageModel_();
- // synch our value *after* we start listening to the collection,
- // since the collection's value might change when a listener is added
- this.value = this.buildValue();
- }
-
- /**
- * Start listening to the model.
- */
- protected abstract void engageModel_();
-
- /**
- * Build and return the current value, as derived from the
- * current state of the wrapped model.
- */
- protected abstract T buildValue();
-
- /**
- * Stop listening to the model and clear the value.
- */
- protected void disengageModel() {
- this.disengageModel_();
- // clear out our value when we are not listening to the collection
- this.value = null;
- }
-
- /**
- * Stop listening to the model.
- */
- protected abstract void disengageModel_();
-
- /**
- * The wrapped model changed in some fashion.
- * Recalculate the value and notify any listeners.
- */
- protected void propertyChanged() {
- Object old = this.value;
- this.value = this.buildValue();
- this.firePropertyChanged(VALUE, old, this.value);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java
deleted file mode 100644
index 8781be4afd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/BufferedWritablePropertyValueModel.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * A BufferedPropertyValueModel is used to hold a temporary copy of the value
- * in another property value model (the "wrapped" value holder). The application
- * can modify this temporary copy, ad nauseam; but the temporary copy is only
- * passed through to the "wrapped" value holder when the trigger "accepts" the
- * buffered value. Alternatively, the application can "reset" the buffered value
- * to the original, "wrapped" value.
- *
- * The trigger is another value model that holds a Boolean and the application
- * changes the trigger's value to true on "accept", false on "reset". Typically,
- * in a dialog:
- * - pressing the OK button will trigger an "accept" and close the dialog
- * - pressing the Cancel button will simply close the dialog,
- * dropping the "buffered" values into the bit bucket
- * - pressing the Apply button will trigger an "accept" and leave the dialog open
- * - pressing the Restore button will trigger a "reset" and leave the dialog open
- *
- * A number of buffered property value models can wrap another set of
- * property aspect adapters that adapt the various aspects of a single
- * domain model. All the bufferd property value models can be hooked to the
- * same trigger, and that trigger is controlled by the application, typically
- * via the OK button in a dialog.
- *
- * @see PropertyAspectAdapter
- */
-public class BufferedWritablePropertyValueModel<T>
- extends PropertyValueModelWrapper<T>
- implements WritablePropertyValueModel<T>
-{
-
- /**
- * We cache the value here until it is accepted and passed
- * through to the wrapped value holder.
- */
- protected T bufferedValue;
-
- /**
- * This is set to true when we are "accepting" the buffered value
- * and passing it through to the wrapped value holder. This allows
- * us to ignore the property change event fired by the wrapped
- * value holder.
- * (We can't stop listening to the wrapped value holder, because
- * if we are the only listener that could "deactivate" the wrapped
- * value holder.)
- */
- protected boolean accepting;
-
- /**
- * This is the trigger that indicates whether the buffered value
- * should be accepted or reset.
- */
- protected final PropertyValueModel<Boolean> triggerHolder;
-
- /** This listens to the trigger holder. */
- protected final PropertyChangeListener triggerChangeListener;
-
- /**
- * This flag indicates whether our buffered value has been assigned
- * a value and is possibly out of synch with the wrapped value.
- */
- protected boolean buffering;
-
-
- // ********** constructors **********
-
- /**
- * Construct a buffered property value model with the specified wrapped
- * property value model and trigger holder.
- */
- public BufferedWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, PropertyValueModel<Boolean> triggerHolder) {
- super(valueHolder);
- if (triggerHolder == null) {
- throw new NullPointerException();
- }
- this.triggerHolder = triggerHolder;
- this.bufferedValue = null;
- this.buffering = false;
- this.accepting = false;
- this.triggerChangeListener = this.buildTriggerChangeListener();
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildTriggerChangeListener() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- BufferedWritablePropertyValueModel.this.triggerChanged(event);
- }
- @Override
- public String toString() {
- return "trigger change listener";
- }
- };
- }
-
-
- // ********** ValueModel implementation **********
-
- /**
- * If we are currently "buffering" a value, return that;
- * otherwise, return the wrapped value.
- */
- public T getValue() {
- return this.buffering ? this.bufferedValue : this.valueHolder.getValue();
- }
-
- /**
- * Assign the new value to our "buffered" value.
- * It will be forwarded to the wrapped value holder
- * when the trigger is "accepted".
- */
- public void setValue(T value) {
- Object old = this.getValue();
- this.bufferedValue = value;
- this.buffering = true;
- this.firePropertyChanged(VALUE, old, this.bufferedValue);
- }
-
-
- // ********** PropertyValueModelWrapper extensions **********
-
- /**
- * extend to engage the trigger holder also
- */
- @Override
- protected void engageValueHolder() {
- super.engageValueHolder();
- this.triggerHolder.addPropertyChangeListener(VALUE, this.triggerChangeListener);
- }
-
- /**
- * extend to disengage the trigger holder also
- */
- @Override
- protected void disengageValueHolder() {
- this.triggerHolder.removePropertyChangeListener(VALUE, this.triggerChangeListener);
- super.disengageValueHolder();
- }
-
-
- // ********** behavior **********
-
- /**
- * If we do not yet have a "buffered" value, simply propagate the
- * change notification with the buffered model as the source.
- * If we do have a "buffered" value, do nothing.
- */
- @Override
- protected void valueChanged(PropertyChangeEvent event) {
- if (this.accepting) {
- // if we are currently "accepting" the value, ignore change notifications,
- // since we caused them and our own listeners are already aware of the change
- return;
- }
- if (this.buffering) {
- this.handleChangeConflict(event);
- } else {
- this.firePropertyChanged(event.cloneWithSource(this));
- }
- }
-
- /**
- * By default, if we have a "buffered" value and the "wrapped" value changes,
- * we simply ignore the new "wrapped" value and simply overlay it with the
- * "buffered" value if it is "accepted". ("Last One In Wins" concurrency model)
- * Subclasses can override this method to change that behavior with a
- * different concurrency model. For example, you could drop the "buffered" value
- * and replace it with the new "wrapped" value, or you could throw an
- * exception.
- */
- protected void handleChangeConflict(PropertyChangeEvent event) {
- // the default is to do nothing
- }
-
- /**
- * The trigger changed:
- * If it is now true, "accept" the buffered value and forward
- * it to the wrapped value holder.
- * If it is now false, "reset" the buffered value to its original value.
- */
- protected void triggerChanged(PropertyChangeEvent event) {
- if ( ! this.buffering) {
- // if nothing has been "buffered", we don't need to do anything:
- // nothing needs to be passed through; nothing needs to be reset;
- return;
- }
- if (((Boolean) event.getNewValue()).booleanValue()) {
- // set the accepting flag so we ignore any events
- // fired by the wrapped value holder
- this.accepting = true;
- this.valueHolder().setValue(this.bufferedValue);
- this.bufferedValue = null;
- this.buffering = false;
- // clear the flag once the "accept" is complete
- this.accepting = false;
- } else {
- // notify our listeners that our value has been reset
- Object old = this.bufferedValue;
- this.bufferedValue = null;
- this.buffering = false;
- this.firePropertyChanged(VALUE, old, this.valueHolder.getValue());
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.getValue());
- }
-
-
- // ********** convenience methods **********
-
- /**
- * Return whether the buffered model is currently "buffering"
- * a value.
- */
- public boolean isBuffering() {
- return this.buffering;
- }
-
- /**
- * Our constructor accepts only a WritablePropertyValueModel<T>.
- */
- @SuppressWarnings("unchecked")
- protected WritablePropertyValueModel<T> valueHolder() {
- return (WritablePropertyValueModel<T>) this.valueHolder;
- }
-
-
- // ********** inner class **********
-
- /**
- * Trigger is a special property value model that only maintains its
- * value (of true or false) during the change notification caused by
- * the #setValue(Object) method. In other words, a Trigger object
- * only has a valid value
- */
- public static class Trigger extends SimplePropertyValueModel<Boolean> {
-
-
- // ********** constructor **********
-
- /**
- * Construct a trigger with a null value.
- */
- public Trigger() {
- super();
- }
-
-
- // ********** ValueModel implementation **********
-
- /**
- * Extend so that this method can only be invoked during
- * change notification triggered by #setValue(Object).
- */
- @Override
- public Boolean getValue() {
- if (this.value == null) {
- throw new IllegalStateException("The method Trigger.value() may only be called during change notification.");
- }
- return this.value;
- }
-
- /**
- * Extend to reset the value to null once all the
- * listeners have been notified.
- */
- @Override
- public void setValue(Boolean value) {
- super.setValue(value);
- this.value = null;
- }
-
-
- // ********** convenience methods **********
-
- /**
- * Set the trigger's value:
- * - true indicates "accept"
- * - false indicates "reset"
- */
- public void setValue(boolean value) {
- this.setValue(Boolean.valueOf(value));
- }
-
- /**
- * Return the trigger's value:
- * - true indicates "accept"
- * - false indicates "reset"
- */
- public boolean booleanValue() {
- return this.getValue().booleanValue();
- }
-
- /**
- * Accept the trigger (i.e. set its value to true).
- */
- public void accept() {
- this.setValue(true);
- }
-
- /**
- * Return whether the trigger has been accepted
- * (i.e. its value was changed to true).
- */
- public boolean isAccepted() {
- return this.booleanValue();
- }
-
- /**
- * Reset the trigger (i.e. set its value to false).
- */
- public void reset() {
- this.setValue(false);
- }
-
- /**
- * Return whether the trigger has been reset
- * (i.e. its value was changed to false).
- */
- public boolean isReset() {
- return ! this.booleanValue();
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationPropertyValueModel.java
deleted file mode 100644
index a2d1e6157d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationPropertyValueModel.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.Transformer;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * A <code>CachingTransformationPropertyValueModel</code> wraps another
- * <code>PropertyValueModel</code> and uses a <code>Transformer</code>
- * to transform the wrapped value before it is returned by <code>getValue()</code>.
- * The transformed value is calculated and cached during initialization and every
- * time the wrapped value changes. This can be useful when the old value
- * passed in to <code>valueChanged(PropertyChangeEvent)</code> can no longer
- * be "transformed" because its state is no longer valid.
- * This caching can also improve time performance in some situations.
- * <p>
- * As an alternative to building a <code>Transformer</code>,
- * a subclass of <code>CachingTransformationPropertyValueModel</code> can
- * either override the <code>transform_(Object)</code> method or,
- * if something other than null should be returned when the wrapped value
- * is null, override the <code>transform(Object)</code> method.
- */
-public class CachingTransformationPropertyValueModel<T1, T2>
- extends TransformationPropertyValueModel<T1, T2>
-{
-
- /**
- * Cache the transformed value so that during property change event notification
- * we do not have to transform the old value. The old value could no longer be valid in
- * the model; as a result, transforming it would not be valid.
- */
- protected T2 cachedValue;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a property value model with the specified nested
- * property value model and the default transformer.
- * Use this constructor if you want to override the
- * <code>transform_(Object)</code> or <code>transform(Object)</code>
- * method instead of building a <code>Transformer</code>.
- */
- public CachingTransformationPropertyValueModel(PropertyValueModel<? extends T1> valueHolder) {
- super(valueHolder);
- }
-
- /**
- * Construct an property value model with the specified nested
- * property value model and transformer.
- */
- public CachingTransformationPropertyValueModel(PropertyValueModel<? extends T1> valueHolder, Transformer<T1, T2> transformer) {
- super(valueHolder, transformer);
- }
-
-
- // ********** behavior **********
-
- /**
- * We have listeners, transform the nested value and cache the result.
- */
- @Override
- protected void engageValueHolder() {
- super.engageValueHolder();
- this.cachedValue = this.transform(this.valueHolder.getValue());
- }
-
- /**
- * We have no more listeners, clear the cached value.
- */
- @Override
- protected void disengageValueHolder() {
- this.cachedValue = null;
- super.disengageValueHolder();
- }
-
- /**
- * No need to transform the nested value, simply return the cached value,
- * which is already transformed.
- */
- @Override
- public T2 getValue() {
- return this.cachedValue;
- }
-
- /**
- * Transform the specified new value, caching it before returning it.
- */
- @Override
- protected T2 transformNew(T1 value) {
- this.cachedValue = super.transformNew(value);
- return this.cachedValue;
- }
-
- /**
- * No need to transform the old value, simply return the cached value,
- * which is already transformed.
- */
- @Override
- protected T2 transformOld(T1 value) {
- return this.cachedValue;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationWritablePropertyValueModel.java
deleted file mode 100644
index 18b6ce0bdc..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CachingTransformationWritablePropertyValueModel.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.BidiTransformer;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * A <code>CachingTransformationWritablePropertyValueModel<code> augments the
- * behavior of a <code>TransformationWritablePropertyValueModel<code> by caching
- * the transformed value.
- * The transformed value is calculated and cached during initialization and every
- * time the wrapped value changes. This can be useful when the old value
- * passed in to <code>valueChanged(PropertyChangeEvent)</code> can no longer
- * be "transformed" because its state is no longer valid.
- * This caching can also improve time performance in some situations.
- */
-public class CachingTransformationWritablePropertyValueModel<T1, T2>
- extends TransformationWritablePropertyValueModel<T1, T2>
-{
-
- /**
- * Cache the transformed value so that during property change event notification
- * we do not have to transform the old value. The old value could no longer be valid in
- * the model; as a result, transforming it would not be valid.
- */
- protected T2 cachedValue;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a writable property value model with the specified nested
- * writable property value model and the default bidi transformer.
- * Use this constructor if you want to override the
- * <code>transform_(Object)</code> and <code>reverseTransform_(Object)</code>
- * (or <code>transform(Object)</code> and <code>reverseTransform(Object)</code>)
- * methods instead of building a <code>BidiTransformer</code>.
- */
- public CachingTransformationWritablePropertyValueModel(WritablePropertyValueModel<T1> valueHolder) {
- super(valueHolder);
- }
-
- /**
- * Construct a writable property value model with the specified nested
- * writable property value model and bidi transformer.
- */
- public CachingTransformationWritablePropertyValueModel(WritablePropertyValueModel<T1> valueHolder, BidiTransformer<T1, T2> transformer) {
- super(valueHolder, transformer);
- }
-
-
- // ********** behavior **********
-
- /**
- * We have listeners, transform the nested value and cache the result.
- */
- @Override
- protected void engageValueHolder() {
- super.engageValueHolder();
- this.cachedValue = this.transform(this.valueHolder.getValue());
- }
-
- /**
- * We have no more listeners, clear the cached value.
- */
- @Override
- protected void disengageValueHolder() {
- this.cachedValue = null;
- super.disengageValueHolder();
- }
-
- /**
- * No need to transform the nested value, simply return the cached value,
- * which is already transformed.
- */
- @Override
- public T2 getValue() {
- return this.cachedValue;
- }
-
- /**
- * Transform the specified new value, caching it before returning it.
- */
- @Override
- protected T2 transformNew(T1 value) {
- this.cachedValue = super.transformNew(value);
- return this.cachedValue;
- }
-
- /**
- * No need to transform the old value, simply return the cached value,
- * which is already transformed.
- */
- @Override
- protected T2 transformOld(T1 value) {
- return this.cachedValue;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java
deleted file mode 100644
index f55783e8a9..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionAspectAdapter.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This extension of AspectAdapter provides CollectionChange support.
- * This allows us to convert a set of one or more collections into
- * a single collection, VALUES.
- *
- * The typical subclass will override the following methods:
- * #iterator_()
- * at the very minimum, override this method to return an iterator on the
- * subject's collection aspect; it does not need to be overridden if
- * #iterator() is overridden and its behavior changed
- * #size_()
- * override this method to improve performance; it does not need to be overridden if
- * #size() is overridden and its behavior changed
- * #iterator()
- * override this method only if returning an empty iterator when the
- * subject is null is unacceptable
- * #size()
- * override this method only if returning a zero when the
- * subject is null is unacceptable
- */
-public abstract class CollectionAspectAdapter<S extends Model, E>
- extends AspectAdapter<S>
- implements CollectionValueModel<E>
-{
- /**
- * The name of the subject's collections that we use for the value.
- */
- protected final String[] collectionNames;
- protected static final String[] EMPTY_COLLECTION_NAMES = new String[0];
-
- /** A listener that listens to the subject's collection aspect. */
- protected final CollectionChangeListener collectionChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a CollectionAspectAdapter for the specified subject
- * and collection.
- */
- protected CollectionAspectAdapter(String collectionName, S subject) {
- this(new String[] {collectionName}, subject);
- }
-
- /**
- * Construct a CollectionAspectAdapter for the specified subject
- * and collections.
- */
- protected CollectionAspectAdapter(String[] collectionNames, S subject) {
- this(new StaticPropertyValueModel<S>(subject), collectionNames);
- }
-
- /**
- * Construct a CollectionAspectAdapter for the specified subject holder
- * and collections.
- */
- protected CollectionAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... collectionNames) {
- super(subjectHolder);
- this.collectionNames = collectionNames;
- this.collectionChangeListener = this.buildCollectionChangeListener();
- }
-
- /**
- * Construct a CollectionAspectAdapter for the specified subject holder
- * and collections.
- */
- protected CollectionAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> collectionNames) {
- this(subjectHolder, collectionNames.toArray(new String[collectionNames.size()]));
- }
-
- /**
- * Construct a CollectionAspectAdapter for an "unchanging" collection in
- * the specified subject. This is useful for a collection aspect that does not
- * change for a particular subject; but the subject will change, resulting in
- * a new collection.
- */
- protected CollectionAspectAdapter(PropertyValueModel<? extends S> subjectHolder) {
- this(subjectHolder, EMPTY_COLLECTION_NAMES);
- }
-
-
- // ********** initialization **********
-
- /**
- * The subject's collection aspect has changed, notify the listeners.
- */
- protected CollectionChangeListener buildCollectionChangeListener() {
- // transform the subject's collection change events into VALUE collection change events
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- CollectionAspectAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- CollectionAspectAdapter.this.itemsRemoved(event);
- }
- public void collectionCleared(CollectionChangeEvent event) {
- CollectionAspectAdapter.this.collectionCleared(event);
- }
- public void collectionChanged(CollectionChangeEvent event) {
- CollectionAspectAdapter.this.collectionChanged(event);
- }
- @Override
- public String toString() {
- return "collection change listener: " + Arrays.asList(CollectionAspectAdapter.this.collectionNames);
- }
- };
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- /**
- * Return the elements of the subject's collection aspect.
- */
- public Iterator<E> iterator() {
- return (this.subject == null) ? EmptyIterator.<E>instance() : this.iterator_();
- }
-
- /**
- * Return the elements of the subject's collection aspect.
- * At this point we can be sure that the subject is not null.
- * @see #iterator()
- */
- protected Iterator<E> iterator_() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Return the size of the subject's collection aspect.
- */
- public int size() {
- return (this.subject == null) ? 0 : this.size_();
- }
-
- /**
- * Return the size of the subject's collection aspect.
- * At this point we can be sure that the subject is not null.
- * @see #size()
- */
- protected int size_() {
- return CollectionTools.size(this.iterator());
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Object getValue() {
- return this.iterator();
- }
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return CollectionChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return VALUES;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyCollectionChangeListeners(VALUES);
- }
-
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.fireCollectionChanged(VALUES);
- }
-
- @Override
- protected void engageSubject_() {
- for (String collectionName : this.collectionNames) {
- ((Model) this.subject).addCollectionChangeListener(collectionName, this.collectionChangeListener);
- }
- }
-
- @Override
- protected void disengageSubject_() {
- for (String collectionName : this.collectionNames) {
- ((Model) this.subject).removeCollectionChangeListener(collectionName, this.collectionChangeListener);
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- for (int i = 0; i < this.collectionNames.length; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(this.collectionNames[i]);
- }
- }
-
-
- // ********** behavior **********
-
- protected void itemsAdded(CollectionChangeEvent event) {
- this.fireItemsAdded(event.cloneWithSource(this, VALUES));
- }
-
- protected void itemsRemoved(CollectionChangeEvent event) {
- this.fireItemsRemoved(event.cloneWithSource(this, VALUES));
- }
-
- protected void collectionCleared(CollectionChangeEvent event) {
- this.fireCollectionCleared(VALUES); // nothing from original event to forward
- }
-
- protected void collectionChanged(CollectionChangeEvent event) {
- this.fireCollectionChanged(VALUES); // nothing from original event to forward
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java
deleted file mode 100644
index 6c236ab78f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionListValueModelAdapter.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * An adapter that allows us to make a CollectionValueModel behave like
- * a read-only ListValueModel, sorta.
- *
- * To maintain a reasonably consistent appearance to client code, we
- * keep an internal list somewhat in synch with the wrapped collection.
- *
- * NB: Since we only listen to the wrapped collection when we have
- * listeners ourselves and we can only stay in synch with the wrapped
- * collection while we are listening to it, results to various methods
- * (e.g. #size(), getItem(int)) will be unpredictable whenever
- * we do not have any listeners. This should not be too painful since,
- * most likely, client objects will also be listeners.
- */
-public class CollectionListValueModelAdapter<E>
- extends AbstractModel
- implements ListValueModel<E>
-{
- /** The wrapped collection value model. */
- protected final CollectionValueModel<? extends E> collectionHolder;
-
- /** A listener that forwards any events fired by the collection holder. */
- protected final CollectionChangeListener collectionChangeListener;
-
- /**
- * Our internal list, which holds the same elements as
- * the wrapped collection, but keeps them in order.
- */
- // we declare this an ArrayList so we can use #clone() and #ensureCapacity(int)
- protected final ArrayList<E> list;
-
-
- // ********** constructors **********
-
- /**
- * Wrap the specified CollectionValueModel.
- */
- public CollectionListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder) {
- super();
- if (collectionHolder == null) {
- throw new NullPointerException();
- }
- this.collectionHolder = collectionHolder;
- this.collectionChangeListener = this.buildCollectionChangeListener();
- this.list = new ArrayList<E>();
- // postpone building the list and listening to the underlying collection
- // until we have listeners ourselves...
- }
-
-
- // ********** initialization **********
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, ListChangeListener.class, LIST_VALUES);
- }
-
- /**
- * The wrapped collection has changed, forward an equivalent
- * list change event to our listeners.
- */
- protected CollectionChangeListener buildCollectionChangeListener() {
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- CollectionListValueModelAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- CollectionListValueModelAdapter.this.itemsRemoved(event);
- }
- public void collectionCleared(CollectionChangeEvent event) {
- CollectionListValueModelAdapter.this.collectionCleared(event);
- }
- public void collectionChanged(CollectionChangeEvent event) {
- CollectionListValueModelAdapter.this.collectionChanged(event);
- }
- @Override
- public String toString() {
- return "collection change listener";
- }
- };
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E> listIterator() {
- return new ReadOnlyListIterator<E>(this.list);
- }
-
- public E get(int index) {
- return this.list.get(index);
- }
-
- public int size() {
- return this.list.size();
- }
-
- public Object[] toArray() {
- return this.list.toArray();
- }
-
-
- // ********** extend change support **********
-
- /**
- * Override to start listening to the collection holder if necessary.
- */
- @Override
- public void addListChangeListener(ListChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addListChangeListener(listener);
- }
-
- /**
- * Override to start listening to the collection holder if necessary.
- */
- @Override
- public void addListChangeListener(String listName, ListChangeListener listener) {
- if (listName == LIST_VALUES && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addListChangeListener(listName, listener);
- }
-
- /**
- * Override to stop listening to the collection holder if appropriate.
- */
- @Override
- public void removeListChangeListener(ListChangeListener listener) {
- super.removeListChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Override to stop listening to the collection holder if appropriate.
- */
- @Override
- public void removeListChangeListener(String listName, ListChangeListener listener) {
- super.removeListChangeListener(listName, listener);
- if (listName == LIST_VALUES && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** queries **********
-
- protected boolean hasListeners() {
- return this.hasAnyListChangeListeners(LIST_VALUES);
- }
-
- protected boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
- /**
- * Return the index of the specified item, using object
- * identity instead of equality.
- */
- protected int lastIdentityIndexOf(Object o) {
- return this.lastIdentityIndexOf(o, this.list.size());
- }
-
- /**
- * Return the last index of the specified item, starting just before the
- * the specified endpoint, and using object identity instead of equality.
- */
- protected int lastIdentityIndexOf(Object o, int end) {
- for (int i = end; i-- > 0; ) {
- if (this.list.get(i) == o) {
- return i;
- }
- }
- return -1;
- }
-
-
- // ********** behavior **********
-
- protected void buildList() {
- Iterator<? extends E> stream = this.collectionHolder.iterator();
- // if the new collection is empty, do nothing
- if (stream.hasNext()) {
- this.list.ensureCapacity(this.collectionHolder.size());
- while (stream.hasNext()) {
- this.list.add(stream.next());
- }
- this.postBuildList();
- }
- }
-
- /**
- * Allow subclasses to manipulate the internal list before
- * sending out change notification.
- */
- protected void postBuildList() {
- // the default is to do nothing...
- }
-
- protected void engageModel() {
- this.collectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener);
- // synch our list *after* we start listening to the collection holder,
- // since its value might change when a listener is added
- this.buildList();
- }
-
- protected void disengageModel() {
- this.collectionHolder.removeCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener);
- // clear out the list when we are not listening to the collection holder
- this.list.clear();
- }
-
- protected void itemsAdded(CollectionChangeEvent e) {
- this.addItemsToList(this.indexToAddItems(), CollectionTools.list(this.items(e)), this.list, LIST_VALUES);
- }
-
- protected int indexToAddItems() {
- return this.list.size();
- }
-
- @SuppressWarnings("unchecked")
- protected Iterator<E> items(CollectionChangeEvent e) {
- return (Iterator<E>) e.items();
- }
-
- protected void itemsRemoved(CollectionChangeEvent e) {
- // we have to remove the items individually,
- // since they are probably not in sequence
- for (Iterator<E> stream = this.items(e); stream.hasNext(); ) {
- this.removeItemFromList(this.lastIdentityIndexOf(stream.next()), this.list, LIST_VALUES);
- }
- }
-
- protected void collectionCleared(CollectionChangeEvent e) {
- this.clearList(this.list, LIST_VALUES);
- }
-
- /**
- * synchronize our internal list with the wrapped collection
- * and fire the appropriate events
- */
- protected void collectionChanged(CollectionChangeEvent e) {
- // put in empty check so we don't fire events unnecessarily
- if ( ! this.list.isEmpty()) {
- @SuppressWarnings("unchecked")
- ArrayList<E> removedItems = (ArrayList<E>) this.list.clone();
- this.list.clear();
- this.fireItemsRemoved(LIST_VALUES, 0, removedItems);
- }
-
- this.buildList();
- // put in empty check so we don't fire events unnecessarily
- if ( ! this.list.isEmpty()) {
- this.fireItemsAdded(LIST_VALUES, 0, this.list);
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.collectionHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java
deleted file mode 100644
index a28ff711db..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a collection value model, "lazily" listen to it, and convert
- * its change notifications into property value model change
- * notifications.
- *
- * Subclasses must override:
- * - #buildValue()
- * to return the current property value, as derived from the
- * current collection value
- *
- * Subclasses might want to override:
- * - #itemsAdded(CollectionChangeEvent event)
- * - #itemsRemoved(CollectionChangeEvent event)
- * - #collectionCleared(CollectionChangeEvent event)
- * - #collectionChanged(CollectionChangeEvent event)
- * to improve performance (by not recalculating the value, if possible)
- */
-public abstract class CollectionPropertyValueModelAdapter<T>
- extends AspectPropertyValueModelAdapter<T>
-{
- /** The wrapped collection value model. */
- protected final CollectionValueModel<?> collectionHolder;
-
- /** A listener that allows us to synch with changes to the wrapped collection holder. */
- protected final CollectionChangeListener collectionChangeListener;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * collection value model.
- */
- protected CollectionPropertyValueModelAdapter(CollectionValueModel<?> collectionHolder) {
- super();
- this.collectionHolder = collectionHolder;
- this.collectionChangeListener = this.buildCollectionChangeListener();
- }
-
- protected CollectionChangeListener buildCollectionChangeListener() {
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- CollectionPropertyValueModelAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- CollectionPropertyValueModelAdapter.this.itemsRemoved(event);
- }
- public void collectionCleared(CollectionChangeEvent event) {
- CollectionPropertyValueModelAdapter.this.collectionCleared(event);
- }
- public void collectionChanged(CollectionChangeEvent event) {
- CollectionPropertyValueModelAdapter.this.collectionChanged(event);
- }
- @Override
- public String toString() {
- return "collection change listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the collection holder.
- */
- @Override
- protected void engageModel_() {
- this.collectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener);
- }
-
- /**
- * Stop listening to the collection holder.
- */
- @Override
- protected void disengageModel_() {
- this.collectionHolder.removeCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.collectionHolder);
- }
-
-
- // ********** collection change support **********
-
- /**
- * Items were added to the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected void itemsAdded(CollectionChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were removed from the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected void itemsRemoved(CollectionChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The wrapped collection holder was cleared;
- * propagate the change notification appropriately.
- */
- protected void collectionCleared(CollectionChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The value of the wrapped collection holder has changed;
- * propagate the change notification appropriately.
- */
- protected void collectionChanged(CollectionChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java
deleted file mode 100644
index 4190fe1d41..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CollectionValueModelWrapper.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * another collection value model, "lazily" listen to it, and propagate
- * its change notifications.
- */
-public abstract class CollectionValueModelWrapper<E>
- extends AbstractModel
-{
-
- /** The wrapped collection value model. */
- protected final CollectionValueModel<? extends E> collectionHolder;
-
- /** A listener that allows us to synch with changes to the wrapped collection holder. */
- protected final CollectionChangeListener collectionChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a collection value model with the specified wrapped
- * collection value model.
- */
- protected CollectionValueModelWrapper(CollectionValueModel<? extends E> collectionHolder) {
- super();
- this.collectionHolder = collectionHolder;
- this.collectionChangeListener = this.buildCollectionChangeListener();
- }
-
-
- // ********** initialization **********
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, CollectionChangeListener.class, CollectionValueModel.VALUES);
- }
-
- protected CollectionChangeListener buildCollectionChangeListener() {
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- CollectionValueModelWrapper.this.itemsAdded(event);
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- CollectionValueModelWrapper.this.itemsRemoved(event);
- }
- public void collectionCleared(CollectionChangeEvent event) {
- CollectionValueModelWrapper.this.collectionCleared(event);
- }
- public void collectionChanged(CollectionChangeEvent event) {
- CollectionValueModelWrapper.this.collectionChanged(event);
- }
- @Override
- public String toString() {
- return "collection change listener";
- }
- };
- }
-
-
- // ********** extend change support **********
-
- /**
- * Extend to start listening to the nested model if necessary.
- */
- @Override
- public synchronized void addCollectionChangeListener(CollectionChangeListener listener) {
- if (this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) {
- this.engageModel();
- }
- super.addCollectionChangeListener(listener);
- }
-
- /**
- * Extend to start listening to the nested model if necessary.
- */
- @Override
- public synchronized void addCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- if (collectionName == CollectionValueModel.VALUES && this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) {
- this.engageModel();
- }
- super.addCollectionChangeListener(collectionName, listener);
- }
-
- /**
- * Extend to stop listening to the nested model if necessary.
- */
- @Override
- public synchronized void removeCollectionChangeListener(CollectionChangeListener listener) {
- super.removeCollectionChangeListener(listener);
- if (this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to stop listening to the nested model if necessary.
- */
- @Override
- public synchronized void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- super.removeCollectionChangeListener(collectionName, listener);
- if (collectionName == CollectionValueModel.VALUES && this.hasNoCollectionChangeListeners(CollectionValueModel.VALUES)) {
- this.disengageModel();
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the collection holder.
- */
- protected void engageModel() {
- this.collectionHolder.addCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener);
- }
-
- /**
- * Stop listening to the collection holder.
- */
- protected void disengageModel() {
- this.collectionHolder.removeCollectionChangeListener(CollectionValueModel.VALUES, this.collectionChangeListener);
- }
-
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected Iterator<E> items(CollectionChangeEvent event) {
- return (Iterator<E>) event.items();
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.collectionHolder);
- }
-
-
- // ********** collection change support **********
-
- /**
- * Items were added to the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected abstract void itemsAdded(CollectionChangeEvent event);
-
- /**
- * Items were removed from the wrapped collection holder;
- * propagate the change notification appropriately.
- */
- protected abstract void itemsRemoved(CollectionChangeEvent event);
-
- /**
- * The wrapped collection holder was cleared;
- * propagate the change notification appropriately.
- */
- protected abstract void collectionCleared(CollectionChangeEvent event);
-
- /**
- * The value of the wrapped collection holder has changed;
- * propagate the change notification appropriately.
- */
- protected abstract void collectionChanged(CollectionChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java
deleted file mode 100644
index 815e48e54c..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeCollectionValueModel.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.NullList;
-import org.eclipse.jpt.utility.internal.Transformer;
-import org.eclipse.jpt.utility.internal.iterators.CompositeIterator;
-import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * A <code>CompositeCollectionValueModel</code> wraps another
- * <code>CollectionValueModel</code> and uses a <code>Transformer</code>
- * to convert each item in the wrapped collection to yet another
- * <code>CollectionValueModel</code>. This composite collection contains
- * the combined items from all these component collections.
- *
- * NB: The wrapped collection must be an "identity set" that does not
- * contain the same item twice or this class will throw an exception.
- *
- * Terminology:
- * - sources - the items in the wrapped collection value model; these
- * are converted into component CVMs by the transformer
- * - component CVMs - the component collection value models that are combined
- * by this composite collection value model
- * - items - the items held by the component CVMs
- */
-public class CompositeCollectionValueModel<E1, E2>
- extends CollectionValueModelWrapper<E1>
- implements CollectionValueModel<E2>
-{
- /**
- * This is the (optional) user-supplied object that transforms
- * the items in the wrapped collection to collection value models.
- */
- private final Transformer<E1, CollectionValueModel<E2>> transformer;
-
- /**
- * Cache of the component collection value models that
- * were generated by the transformer; keyed by the item
- * in the wrapped collection that was passed to the transformer.
- */
- private final IdentityHashMap<E1, CollectionValueModel<E2>> componentCVMs;
-
- /**
- * Cache of the collections corresponding to the component
- * collection value models above; keyed by the component
- * collection value models.
- * Use ArrayLists so we can use ArrayList-specific methods
- * (e.g. #clone() and #ensureCapacity()).
- */
- private final IdentityHashMap<CollectionValueModel<E2>, ArrayList<E2>> collections;
-
- /** Listener that listens to all the component collection value models. */
- private final CollectionChangeListener componentCVMListener;
-
- /** Cache the size of the composite collection. */
- private int size;
-
-
- // ********** constructors **********
-
- /**
- * Construct a collection value model with the specified wrapped
- * collection value model. Use this constructor if
- * - the wrapped collection value model already contains other
- * collection value models or
- * - you want to override the <code>transform(E1)</code> method
- * instead of building a <code>Transformer</code>
- */
- public CompositeCollectionValueModel(CollectionValueModel<? extends E1> collectionHolder) {
- this(collectionHolder, Transformer.Null.<E1, CollectionValueModel<E2>>instance());
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * collection value model and transformer.
- */
- public CompositeCollectionValueModel(CollectionValueModel<? extends E1> collectionHolder, Transformer<E1, CollectionValueModel<E2>> transformer) {
- super(collectionHolder);
- this.transformer = transformer;
- this.componentCVMs = new IdentityHashMap<E1, CollectionValueModel<E2>>();
- this.collections = new IdentityHashMap<CollectionValueModel<E2>, ArrayList<E2>>();
- this.componentCVMListener = this.buildComponentListener();
- this.size = 0;
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * list value model. Use this constructor if
- * - the wrapped list value model already contains collection
- * value models or
- * - you want to override the <code>transform(E1)</code> method
- * instead of building a <code>Transformer</code>
- */
- public CompositeCollectionValueModel(ListValueModel<? extends E1> listHolder) {
- this(new ListCollectionValueModelAdapter<E1>(listHolder));
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * list value model and transformer.
- */
- public CompositeCollectionValueModel(ListValueModel<? extends E1> listHolder, Transformer<E1, CollectionValueModel<E2>> transformer) {
- this(new ListCollectionValueModelAdapter<E1>(listHolder), transformer);
- }
-
- /**
- * Construct a collection value model with the specified, unchanging, wrapped
- * collection. Use this constructor if
- * - the wrapped collection already contains collection
- * value models or
- * - you want to override the <code>transform(E1)</code> method
- * instead of building a <code>Transformer</code>
- */
- public CompositeCollectionValueModel(Collection<? extends E1> collection) {
- this(new StaticCollectionValueModel<E1>(collection));
- }
-
- /**
- * Construct a collection value model with the specified, unchanging, wrapped
- * collection and transformer.
- */
- public CompositeCollectionValueModel(Collection<? extends E1> collection, Transformer<E1, CollectionValueModel<E2>> transformer) {
- this(new StaticCollectionValueModel<E1>(collection), transformer);
- }
-
-
- // ********** initialization **********
-
- protected CollectionChangeListener buildComponentListener() {
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- CompositeCollectionValueModel.this.componentItemsAdded(event);
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- CompositeCollectionValueModel.this.componentItemsRemoved(event);
- }
- public void collectionCleared(CollectionChangeEvent event) {
- CompositeCollectionValueModel.this.componentCollectionCleared(event);
- }
- public void collectionChanged(CollectionChangeEvent event) {
- CompositeCollectionValueModel.this.componentCollectionChanged(event);
- }
- @Override
- public String toString() {
- return "component listener";
- }
- };
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- public Iterator<E2> iterator() {
- return new CompositeIterator<E2>(this.buildCollectionsIterators());
- }
-
- protected Iterator<Iterator<E2>> buildCollectionsIterators() {
- return new TransformationIterator<ArrayList<E2>, Iterator<E2>>(this.collections.values().iterator()) {
- @Override
- protected Iterator<E2> transform(ArrayList<E2> next) {
- return next.iterator();
- }
- };
- }
-
- public int size() {
- return this.size;
- }
-
-
- // ********** CollectionValueModelWrapper overrides/implementation **********
-
- @Override
- protected void engageModel() {
- super.engageModel();
- // synch our cache *after* we start listening to the wrapped collection,
- // since its value might change when a listener is added
- this.addAllComponentSources();
- }
-
- /**
- * Transform all the sources to collection value models
- * and add their items to our cache, with no event notification.
- */
- protected void addAllComponentSources() {
- for (E1 source : this.collectionHolder) {
- this.addComponentSource(source, NullList.<E2>instance());
- }
- }
-
- @Override
- protected void disengageModel() {
- super.disengageModel();
- // stop listening to the components...
- for (CollectionValueModel<E2> componentCVM : this.componentCVMs.values()) {
- componentCVM.removeCollectionChangeListener(VALUES, this.componentCVMListener);
- }
- // ...and clear the cache
- this.componentCVMs.clear();
- this.collections.clear();
- this.size = 0;
- }
-
- /**
- * Some component sources were added;
- * add their corresponding items to our cache.
- */
- @Override
- protected void itemsAdded(CollectionChangeEvent event) {
- ArrayList<E2> addedItems = new ArrayList<E2>();
- for (Iterator<E1> stream = this.items(event); stream.hasNext(); ) {
- this.addComponentSource(stream.next(), addedItems);
- }
- this.fireItemsAdded(VALUES, addedItems);
- }
-
- /**
- * Transform the specified source to a collection value model
- * and add its items to our cache and the "collecting parameter".
- */
- protected void addComponentSource(E1 source, List<E2> addedItems) {
- CollectionValueModel<E2> componentCVM = this.transform(source);
- if (this.componentCVMs.put(source, componentCVM) != null) {
- throw new IllegalStateException("duplicate component: " + source);
- }
- componentCVM.addCollectionChangeListener(VALUES, this.componentCVMListener);
- ArrayList<E2> componentCollection = new ArrayList<E2>(componentCVM.size());
- if (this.collections.put(componentCVM, componentCollection) != null) {
- throw new IllegalStateException("duplicate collection: " + source);
- }
- this.addComponentItems(componentCVM, componentCollection);
- addedItems.addAll(componentCollection);
- }
-
- /**
- * Add the items in the specified component CVM to the specified component
- * collection.
- */
- protected void addComponentItems(CollectionValueModel<E2> componentCVM, ArrayList<E2> componentCollection) {
- int itemsSize = componentCVM.size();
- this.size += itemsSize;
- componentCollection.ensureCapacity(componentCollection.size() + itemsSize);
- CollectionTools.addAll(componentCollection, componentCVM);
- }
-
- /**
- * Some component sources were removed;
- * remove their corresponding items from our cache.
- */
- @Override
- protected void itemsRemoved(CollectionChangeEvent event) {
- ArrayList<E2> removedItems = new ArrayList<E2>();
- for (Iterator<E1> stream = this.items(event); stream.hasNext(); ) {
- this.removeComponentSource(stream.next(), removedItems);
- }
- this.fireItemsRemoved(VALUES, removedItems);
- }
-
- /**
- * Remove the items corresponding to the specified source
- * from our cache.
- */
- protected void removeComponentSource(E1 source, List<E2> removedItems) {
- CollectionValueModel<E2> componentCVM = this.componentCVMs.remove(source);
- if (componentCVM == null) {
- throw new IllegalStateException("missing component: " + source);
- }
- componentCVM.removeCollectionChangeListener(VALUES, this.componentCVMListener);
- ArrayList<E2> componentCollection = this.collections.remove(componentCVM);
- if (componentCollection == null) {
- throw new IllegalStateException("missing collection: " + source);
- }
- removedItems.addAll(componentCollection);
- this.removeComponentItems(componentCollection);
- }
-
- /**
- * Update our size and collection cache.
- */
- protected void removeComponentItems(ArrayList<E2> componentCollection) {
- this.size -= componentCollection.size();
- componentCollection.clear();
- }
-
- /**
- * The component sources cleared;
- * clear our cache.
- */
- @Override
- protected void collectionCleared(CollectionChangeEvent event) {
- this.removeAllComponentSources();
- this.fireCollectionCleared(VALUES);
- }
-
- protected void removeAllComponentSources() {
- // copy the keys so we don't eat our own tail
- ArrayList<E1> copy = new ArrayList<E1>(this.componentCVMs.keySet());
- for (E1 source : copy) {
- this.removeComponentSource(source, NullList.<E2>instance());
- }
- }
-
- /**
- * The component sources changed;
- * rebuild our cache.
- */
- @Override
- protected void collectionChanged(CollectionChangeEvent event) {
- this.removeAllComponentSources();
- this.addAllComponentSources();
- this.fireCollectionChanged(VALUES);
- }
-
-
- // ********** internal methods **********
-
- /**
- * Transform the specified object into a collection value model.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Transformer</code>.
- */
- protected CollectionValueModel<E2> transform(E1 value) {
- return this.transformer.transform(value);
- }
-
- /**
- * One of the component collections had items added;
- * synchronize our caches.
- */
- protected void componentItemsAdded(CollectionChangeEvent event) {
- int itemsSize = event.itemsSize();
- this.size += itemsSize;
-
- ArrayList<E2> componentCollection = this.collections.get(this.componentCVM(event));
- componentCollection.ensureCapacity(componentCollection.size() + itemsSize);
-
- this.addItemsToCollection(this.componentItems(event), componentCollection, VALUES);
- }
-
- /**
- * One of the component collections had items removed;
- * synchronize our caches.
- */
- protected void componentItemsRemoved(CollectionChangeEvent event) {
- this.size -= event.itemsSize();
- ArrayList<E2> componentCollection = this.collections.get(this.componentCVM(event));
- this.removeItemsFromCollection(this.componentItems(event), componentCollection, VALUES);
- }
-
- /**
- * One of the component collections was cleared;
- * synchronize our caches by clearing out the appropriate
- * collection.
- */
- protected void componentCollectionCleared(CollectionChangeEvent event) {
- ArrayList<E2> componentCollection = this.collections.get(this.componentCVM(event));
- ArrayList<E2> removedItems = new ArrayList<E2>(componentCollection);
- this.removeComponentItems(componentCollection);
- this.fireItemsRemoved(VALUES, removedItems);
- }
-
- /**
- * One of the component collections changed;
- * synchronize our caches by clearing out the appropriate
- * collection and then rebuilding it.
- */
- protected void componentCollectionChanged(CollectionChangeEvent event) {
- CollectionValueModel<E2> componentCVM = this.componentCVM(event);
- ArrayList<E2> componentCollection = this.collections.get(componentCVM);
- this.removeComponentItems(componentCollection);
- this.addComponentItems(componentCVM, componentCollection);
- this.fireCollectionChanged(VALUES);
- }
-
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected Iterator<E2> componentItems(CollectionChangeEvent event) {
- return (Iterator<E2>) event.items();
- }
-
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected CollectionValueModel<E2> componentCVM(CollectionChangeEvent event) {
- return (CollectionValueModel<E2>) event.getSource();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java
deleted file mode 100644
index 3609d5a4dd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/CompositeListValueModel.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.Transformer;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyCompositeListIterator;
-import org.eclipse.jpt.utility.internal.iterators.TransformationListIterator;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * A <code>CompositeListValueModel</code> wraps another
- * <code>ListValueModel</code> and uses a <code>Transformer</code>
- * to convert each item in the wrapped list to yet another
- * <code>ListValueModel</code>. This composite list contains
- * the combined items from all these component lists.
- *
- * Terminology:
- * - sources - the items in the wrapped list value model; these
- * are converted into component LVMs by the transformer
- * - componentLVMs - the component list value models that are combined
- * by this composite list value model
- * - items - the items held by the component LVMs
- */
-public class CompositeListValueModel<E1, E2>
- extends ListValueModelWrapper<E1>
- implements ListValueModel<E2>
-{
- /**
- * This is the (optional) user-supplied object that transforms
- * the items in the wrapped list to list value models.
- */
- private final Transformer<E1, ListValueModel<E2>> transformer;
-
- /**
- * Cache of the sources, component LVMs, lists.
- */
- private final ArrayList<Info> infoList;
- protected class Info {
- // the object passed to the transformer
- final E1 source;
- // the list value model generated by the transformer
- final ListValueModel<E2> componentLVM;
- // cache of the items held by the component LVM
- final ArrayList<E2> items;
- // the component LVM's beginning index within the composite LVM
- int begin;
- Info(E1 source, ListValueModel<E2> componentLVM, ArrayList<E2> items, int begin) {
- super();
- this.source = source;
- this.componentLVM = componentLVM;
- this.items = items;
- this.begin = begin;
- }
- }
-
- /** Listener that listens to all the component list value models. */
- private final ListChangeListener componentLVMListener;
-
- /** Cache the size of the composite list. */
- private int size;
-
-
- // ********** constructors **********
-
- /**
- * Construct a list value model with the specified wrapped
- * list value model. Use this constructor if
- * - the wrapped list value model already contains other
- * list value models or
- * - you want to override the <code>transform(E1)</code> method
- * instead of building a <code>Transformer</code>
- */
- public CompositeListValueModel(ListValueModel<? extends E1> listHolder) {
- this(listHolder, Transformer.Null.<E1, ListValueModel<E2>>instance());
- }
-
- /**
- * Construct a list value model with the specified wrapped
- * list value model and transformer.
- */
- public CompositeListValueModel(ListValueModel<? extends E1> listHolder, Transformer<E1, ListValueModel<E2>> transformer) {
- super(listHolder);
- this.transformer = transformer;
- this.infoList = new ArrayList<Info>();
- this.componentLVMListener = this.buildComponentLVMListener();
- this.size = 0;
- }
-
- /**
- * Construct a list value model with the specified, unchanging, wrapped
- * list. Use this constructor if
- * - the wrapped list already contains list value models or
- * - you want to override the <code>transform(E1)</code> method
- * instead of building a <code>Transformer</code>
- */
- public CompositeListValueModel(List<? extends E1> list) {
- this(new StaticListValueModel<E1>(list));
- }
-
- /**
- * Construct a list value model with the specified, unchanging, wrapped
- * list and transformer.
- */
- public CompositeListValueModel(List<? extends E1> list, Transformer<E1, ListValueModel<E2>> transformer) {
- this(new StaticListValueModel<E1>(list), transformer);
- }
-
-
- // ********** initialization **********
-
- protected ListChangeListener buildComponentLVMListener() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- CompositeListValueModel.this.componentItemsAdded(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- CompositeListValueModel.this.componentItemsRemoved(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- CompositeListValueModel.this.componentItemsReplaced(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- CompositeListValueModel.this.componentItemsMoved(event);
- }
- public void listCleared(ListChangeEvent event) {
- CompositeListValueModel.this.componentListCleared(event);
- }
- public void listChanged(ListChangeEvent event) {
- CompositeListValueModel.this.componentListChanged(event);
- }
- @Override
- public String toString() {
- return "component LVM listener";
- }
- };
- }
-
-
- // ********** ListValueModel implementation **********
-
- public E2 get(int index) {
- if ((index < 0) || (index >= this.size)) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size);
- }
- // move backwards through the info list
- for (int i = this.infoList.size(); i-- > 0; ) {
- Info info = this.infoList.get(i);
- if (index >= info.begin) {
- return info.items.get(index - info.begin);
- }
- }
- throw new IllegalStateException(); // something is wack
- }
-
- public Iterator<E2> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E2> listIterator() {
- return new ReadOnlyCompositeListIterator<E2>(this.buildListsIterators());
- }
-
- protected ListIterator<ListIterator<E2>> buildListsIterators() {
- return new TransformationListIterator<Info, ListIterator<E2>>(this.infoList.listIterator()) {
- @Override
- protected ListIterator<E2> transform(Info info) {
- return info.items.listIterator();
- }
- };
- }
-
- public int size() {
- return this.size;
- }
-
- public Object[] toArray() {
- return CollectionTools.array(this.listIterator(), this.size);
- }
-
-
- // ********** ListValueModelWrapper overrides/implementation **********
-
- @Override
- protected void engageModel() {
- super.engageModel();
- // synch our cache *after* we start listening to the wrapped list,
- // since its value might change when a listener is added
- this.addComponentSources(0, this.listHolder.listIterator(), this.listHolder.size());
- }
-
- @Override
- protected void disengageModel() {
- super.disengageModel();
- // stop listening to the component LVMs...
- for (Info info : this.infoList) {
- info.componentLVM.removeListChangeListener(LIST_VALUES, this.componentLVMListener);
- }
- // ...and clear the cache
- this.infoList.clear();
- this.size = 0;
- }
-
- /**
- * Some component sources were added; update our cache.
- */
- @Override
- protected void itemsAdded(ListChangeEvent event) {
- this.addComponentSources(event.getIndex(), this.items(event), event.itemsSize(), true); // true = fire event
- }
-
- /**
- * Do not fire an event.
- */
- protected void addComponentSources(int addedSourcesIndex, ListIterator<? extends E1> addedSources, int addedSourcesSize) {
- this.addComponentSources(addedSourcesIndex, addedSources, addedSourcesSize, false); // false = do not fire event
- }
-
- /**
- * Add infos corresponding to the specified sources to our cache.
- * Fire the appropriate event if requested.
- */
- protected void addComponentSources(int addedSourcesIndex, ListIterator<? extends E1> addedSources, int addedSourcesSize, boolean fireEvent) {
- ArrayList<Info> newInfoList = new ArrayList<Info>(addedSourcesSize);
- // the 'items' are either tacked on to the end or
- // at the 'begin' index of the first 'info' that is being pushed back
- int newItemsIndex = (addedSourcesIndex == this.infoList.size()) ? this.size : this.infoList.get(addedSourcesIndex).begin;
-
- int begin = newItemsIndex;
- while (addedSources.hasNext()) {
- E1 source = addedSources.next();
- ListValueModel<E2> componentLVM = this.transform(source);
- componentLVM.addListChangeListener(LIST_VALUES, this.componentLVMListener);
- ArrayList<E2> items = new ArrayList<E2>(componentLVM.size());
- CollectionTools.addAll(items, componentLVM.listIterator());
- newInfoList.add(new Info(source, componentLVM, items, begin));
- begin += items.size();
- }
- this.infoList.addAll(addedSourcesIndex, newInfoList);
- int newItemsSize = begin - newItemsIndex;
- this.size += newItemsSize;
-
- // bump the 'begin' index for all the infos that were pushed back by the insert
- int movedInfosIndex = addedSourcesIndex + addedSourcesSize;
- for (int i = movedInfosIndex; i < this.infoList.size(); i++) {
- this.infoList.get(i).begin += newItemsSize;
- }
-
- if (fireEvent) {
- ArrayList<E2> newItems = new ArrayList<E2>(newItemsSize);
- for (int i = addedSourcesIndex; i < movedInfosIndex; i++) {
- newItems.addAll(this.infoList.get(i).items);
- }
- this.fireItemsAdded(LIST_VALUES, newItemsIndex, newItems);
- }
- }
-
- /**
- * Some component sources were removed; update our cache.
- */
- @Override
- protected void itemsRemoved(ListChangeEvent event) {
- this.removeComponentSources(event.getIndex(), event.itemsSize(), true); // true = fire event
- }
-
- /**
- * Do not fire an event.
- */
- protected void removeComponentSources(int removedSourcesIndex, int removedSourcesSize) {
- this.removeComponentSources(removedSourcesIndex, removedSourcesSize, false); // false = do not fire event
- }
-
- /**
- * Remove the infos corresponding to the specified sources from our cache.
- */
- protected void removeComponentSources(int removedSourcesIndex, int removedSourcesSize, boolean fireEvent) {
- int removedItemsIndex = this.infoList.get(removedSourcesIndex).begin;
- int movedSourcesIndex = removedSourcesIndex + removedSourcesSize;
- int movedItemsIndex = (movedSourcesIndex == this.infoList.size()) ? this.size : this.infoList.get(movedSourcesIndex).begin;
- int removedItemsSize = movedItemsIndex - removedItemsIndex;
- this.size -= removedItemsSize;
-
- List<Info> subList = this.infoList.subList(removedSourcesIndex, removedSourcesIndex + removedSourcesSize);
- ArrayList<Info> removedInfoList = new ArrayList<Info>(subList); // make a copy
- subList.clear();
-
- // decrement the 'begin' index for all the infos that were moved forward by the deletes
- for (int i = removedSourcesIndex; i < this.infoList.size(); i++) {
- this.infoList.get(i).begin -= removedItemsSize;
- }
-
- for (Info removedInfo : removedInfoList) {
- removedInfo.componentLVM.removeListChangeListener(LIST_VALUES, this.componentLVMListener);
- }
-
- if (fireEvent) {
- ArrayList<E2> removedItems = new ArrayList<E2>(removedItemsSize);
- for (Info removedInfo : removedInfoList) {
- removedItems.addAll(removedInfo.items);
- }
- this.fireItemsRemoved(LIST_VALUES, removedItemsIndex, removedItems);
- }
- }
-
- /**
- * Some component sources were replaced; update our cache.
- */
- @Override
- protected void itemsReplaced(ListChangeEvent event) {
- this.replaceComponentSources(event.getIndex(), this.items(event), event.itemsSize(), true); // true = fire event
- }
-
- /**
- * Replaced component sources will not (typically) map to a set of replaced
- * items, so we remove and add the corresponding lists of items, resulting in
- * two events.
- */
- protected void replaceComponentSources(int replacedSourcesIndex, ListIterator<? extends E1> newSources, int replacedSourcesSize, boolean fireEvent) {
- this.removeComponentSources(replacedSourcesIndex, replacedSourcesSize, fireEvent);
- this.addComponentSources(replacedSourcesIndex, newSources, replacedSourcesSize, fireEvent);
- }
-
- /**
- * Some component sources were moved; update our cache.
- */
- @Override
- protected void itemsMoved(ListChangeEvent event) {
- this.moveComponentSources(event.getTargetIndex(), event.getSourceIndex(), event.getMoveLength(), true); // true = fire event
- }
-
- protected void moveComponentSources(int targetSourcesIndex, int sourceSourcesIndex, int movedSourcesLength, boolean fireEvent) {
- int sourceItemsIndex = this.infoList.get(sourceSourcesIndex).begin;
-
- int nextSourceSourceIndex = sourceSourcesIndex + movedSourcesLength;
- int nextSourceItemIndex = (nextSourceSourceIndex == this.infoList.size()) ? this.size : this.infoList.get(nextSourceSourceIndex).begin;
- int moveItemsLength = nextSourceItemIndex - sourceItemsIndex;
-
- int targetItemsIndex = -1;
- if (sourceSourcesIndex > targetSourcesIndex) {
- // move from high to low index
- targetItemsIndex = this.infoList.get(targetSourcesIndex).begin;
- } else {
- // move from low to high index (higher items move down during move)
- int nextTargetSourceIndex = targetSourcesIndex + movedSourcesLength;
- targetItemsIndex = (nextTargetSourceIndex == this.infoList.size()) ? this.size : this.infoList.get(nextTargetSourceIndex).begin;
- targetItemsIndex = targetItemsIndex - moveItemsLength;
- }
-
- CollectionTools.move(this.infoList, targetSourcesIndex, sourceSourcesIndex, movedSourcesLength);
-
- // update the 'begin' indexes of all the affected 'infos'
- int min = Math.min(targetSourcesIndex, sourceSourcesIndex);
- int max = Math.max(targetSourcesIndex, sourceSourcesIndex) + movedSourcesLength;
- int begin = Math.min(targetItemsIndex, sourceItemsIndex);
- for (int i = min; i < max; i++) {
- Info info = this.infoList.get(i);
- info.begin = begin;
- begin += info.componentLVM.size();
- }
-
- if (fireEvent) {
- this.fireItemsMoved(LIST_VALUES, targetItemsIndex, sourceItemsIndex, moveItemsLength);
- }
- }
-
- /**
- * The component sources were cleared; clear our cache.
- */
- @Override
- protected void listCleared(ListChangeEvent event) {
- this.removeComponentSources(0, this.infoList.size());
- this.fireListCleared(LIST_VALUES);
- }
-
- /**
- * The component sources changed; rebuild our cache.
- */
- @Override
- protected void listChanged(ListChangeEvent event) {
- this.removeComponentSources(0, this.infoList.size());
- this.addComponentSources(0, this.listHolder.listIterator(), this.listHolder.size());
- this.fireListChanged(LIST_VALUES);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(CollectionTools.list(this.listIterator(), this.size));
- }
-
-
- // ********** internal methods **********
-
- /**
- * Transform the specified object into a list value model.
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Transformer</code>.
- */
- protected ListValueModel<E2> transform(E1 value) {
- return this.transformer.transform(value);
- }
-
- /**
- * Return the index of the specified component LVM.
- */
- protected int indexOf(ListValueModel<E2> componentLVM) {
- for (int i = 0; i < this.infoList.size(); i++) {
- if (this.infoList.get(i).componentLVM == componentLVM) {
- return i;
- }
- }
- throw new IllegalArgumentException("invalid component LVM: " + componentLVM);
- }
-
- /**
- * Return the index of the specified event's component LVM.
- */
- protected int indexFor(ListChangeEvent event) {
- return this.indexOf(this.componentLVM(event));
- }
-
- /**
- * Items were added to one of the component lists;
- * synchronize our cache.
- */
- protected void componentItemsAdded(ListChangeEvent event) {
- // update the affected 'begin' indices
- int componentLVMIndex = this.indexFor(event);
- int newItemsSize = event.itemsSize();
- for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) {
- this.infoList.get(i).begin += newItemsSize;
- }
- this.size += newItemsSize;
-
- // synchronize the cached list
- Info info = this.infoList.get(componentLVMIndex);
- CollectionTools.addAll(info.items, event.getIndex(), this.componentItems(event), event.itemsSize());
-
- // translate the event
- this.fireItemsAdded(event.cloneWithSource(this, LIST_VALUES, info.begin));
- }
-
- /**
- * Items were removed from one of the component lists;
- * synchronize our cache.
- */
- protected void componentItemsRemoved(ListChangeEvent event) {
- // update the affected 'begin' indices
- int componentLVMIndex = this.indexFor(event);
- int removedItemsSize = event.itemsSize();
- for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) {
- this.infoList.get(i).begin -= removedItemsSize;
- }
- this.size -= removedItemsSize;
-
- // synchronize the cached list
- Info info = this.infoList.get(componentLVMIndex);
- int itemIndex = event.getIndex();
- info.items.subList(itemIndex, itemIndex + event.itemsSize()).clear();
-
- // translate the event
- this.fireItemsRemoved(event.cloneWithSource(this, LIST_VALUES, info.begin));
- }
-
- /**
- * Items were replaced in one of the component lists;
- * synchronize our cache.
- */
- protected void componentItemsReplaced(ListChangeEvent event) {
- // no changes to the 'begin' indices or size
-
- // synchronize the cached list
- int componentLVMIndex = this.indexFor(event);
- Info info = this.infoList.get(componentLVMIndex);
- int i = event.getIndex();
- for (Iterator<E2> stream = this.componentItems(event); stream.hasNext(); ) {
- info.items.set(i++, stream.next());
- }
-
- // translate the event
- this.fireItemsReplaced(event.cloneWithSource(this, LIST_VALUES, info.begin));
- }
-
- /**
- * Items were moved in one of the component lists;
- * synchronize our cache.
- */
- protected void componentItemsMoved(ListChangeEvent event) {
- // no changes to the 'begin' indices or size
-
- // synchronize the cached list
- int componentLVMIndex = this.indexFor(event);
- Info info = this.infoList.get(componentLVMIndex);
- CollectionTools.move(info.items, event.getTargetIndex(), event.getSourceIndex(), event.getMoveLength());
-
- // translate the event
- this.fireItemsMoved(event.cloneWithSource(this, LIST_VALUES, info.begin));
- }
-
- /**
- * One of the component lists was cleared;
- * synchronize our cache.
- */
- protected void componentListCleared(ListChangeEvent event) {
- int componentLVMIndex = this.indexFor(event);
- this.clearComponentList(componentLVMIndex, this.infoList.get(componentLVMIndex));
- }
-
- protected void clearComponentList(int componentLVMIndex, Info info) {
- // update the affected 'begin' indices
- int removedItemsSize = info.items.size();
- for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) {
- this.infoList.get(i).begin -= removedItemsSize;
- }
- this.size -= removedItemsSize;
-
- // synchronize the cached list
- ArrayList<E2> items = new ArrayList<E2>(info.items);
- info.items.clear();
-
- // translate the event
- this.fireItemsRemoved(LIST_VALUES, info.begin, items);
- }
-
- /**
- * One of the component lists changed;
- * synchronize our cache by clearing out the appropriate
- * list and rebuilding it.
- */
- protected void componentListChanged(ListChangeEvent event) {
- int componentLVMIndex = this.indexFor(event);
- Info info = this.infoList.get(componentLVMIndex);
- this.clearComponentList(componentLVMIndex, info);
-
- // update the affected 'begin' indices
- int newItemsSize = info.componentLVM.size();
- for (int i = componentLVMIndex + 1; i < this.infoList.size(); i++) {
- this.infoList.get(i).begin += newItemsSize;
- }
- this.size += newItemsSize;
-
- // synchronize the cached list
- CollectionTools.addAll(info.items, info.componentLVM.listIterator(), newItemsSize);
-
- // translate the event
- this.fireItemsAdded(LIST_VALUES, info.begin, info.items);
- }
-
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected ListIterator<E2> componentItems(ListChangeEvent event) {
- return (ListIterator<E2>) event.items();
- }
-
- // minimize scope of suppressed warnings
- @SuppressWarnings("unchecked")
- protected ListValueModel<E2> componentLVM(ListChangeEvent event) {
- return (ListValueModel<E2>) event.getSource();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java
deleted file mode 100644
index 84650cf2b8..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ExtendedListValueModelWrapper.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyCompositeListIterator;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * This wrapper extends a ListValueModel (or CollectionValueModel)
- * with fixed collections of items on either end.
- * <p>
- * NB: Be careful using or wrapping this list value model, since the
- * "extended" items may be unexpected by the client code or wrapper.
- */
-public class ExtendedListValueModelWrapper<E>
- extends ListValueModelWrapper<E>
- implements ListValueModel<E>
-{
- /** the items "prepended" to the wrapped list */
- protected List<E> prefix;
-
- /** the items "appended" to the wrapped list */
- protected List<E> suffix;
-
-
- // ********** lots o' constructors **********
-
- /**
- * Extend the specified list with a prefix and suffix.
- */
- public ExtendedListValueModelWrapper(List<? extends E> prefix, ListValueModel<? extends E> listHolder, List<? extends E> suffix) {
- super(listHolder);
- this.prefix = new ArrayList<E>(prefix);
- this.suffix = new ArrayList<E>(suffix);
- }
-
- /**
- * Extend the specified list with a prefix and suffix.
- */
- public ExtendedListValueModelWrapper(E prefix, ListValueModel<? extends E> listHolder, E suffix) {
- super(listHolder);
- this.prefix = Collections.singletonList(prefix);
- this.suffix = Collections.singletonList(suffix);
- }
-
- /**
- * Extend the specified list with a prefix.
- */
- public ExtendedListValueModelWrapper(List<? extends E> prefix, ListValueModel<? extends E> listHolder) {
- super(listHolder);
- this.prefix = new ArrayList<E>(prefix);
- this.suffix = Collections.emptyList();
- }
-
- /**
- * Extend the specified list with a prefix.
- */
- public ExtendedListValueModelWrapper(E prefix, ListValueModel<? extends E> listHolder) {
- super(listHolder);
- this.prefix = Collections.singletonList(prefix);
- this.suffix = Collections.emptyList();
- }
-
- /**
- * Extend the specified list with a suffix.
- */
- public ExtendedListValueModelWrapper(ListValueModel<? extends E> listHolder, List<? extends E> suffix) {
- super(listHolder);
- this.prefix = Collections.emptyList();
- this.suffix = new ArrayList<E>(suffix);
- }
-
- /**
- * Extend the specified list with a suffix.
- */
- public ExtendedListValueModelWrapper(ListValueModel<? extends E> listHolder, E suffix) {
- super(listHolder);
- this.prefix = Collections.emptyList();
- this.suffix = Collections.singletonList(suffix);
- }
-
- /**
- * Extend the specified list with a prefix containing a single null item.
- */
- public ExtendedListValueModelWrapper(ListValueModel<? extends E> listHolder) {
- super(listHolder);
- this.prefix = Collections.singletonList(null);
- this.suffix = Collections.emptyList();
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E> listIterator() {
- return new ReadOnlyListIterator<E>(this.listIterator_());
- }
-
- @SuppressWarnings("unchecked")
- protected ListIterator<E> listIterator_() {
- return new ReadOnlyCompositeListIterator<E>(
- this.prefix.listIterator(),
- this.listHolder.listIterator(),
- this.suffix.listIterator()
- );
- }
-
- public E get(int index) {
- int prefixSize = this.prefix.size();
- if (index < prefixSize) {
- return this.prefix.get(index);
- } else if (index >= prefixSize + this.listHolder.size()) {
- return this.suffix.get(index - (prefixSize + this.listHolder.size()));
- } else {
- return this.listHolder.get(index - prefixSize);
- }
- }
-
- public int size() {
- return this.prefix.size() + this.listHolder.size() + this.suffix.size();
- }
-
- public Object[] toArray() {
- ArrayList<E> list = new ArrayList<E>(this.size());
- list.addAll(this.prefix);
- CollectionTools.addAll(list, this.listHolder.iterator());
- list.addAll(this.suffix);
- return list.toArray();
- }
-
-
- // ********** ListValueModelWrapper implementation/overrides **********
-
- @Override
- protected void itemsAdded(ListChangeEvent event) {
- this.fireItemsAdded(event.cloneWithSource(this, LIST_VALUES, this.prefix.size()));
- }
-
- @Override
- protected void itemsRemoved(ListChangeEvent event) {
- this.fireItemsRemoved(event.cloneWithSource(this, LIST_VALUES, this.prefix.size()));
- }
-
- @Override
- protected void itemsReplaced(ListChangeEvent event) {
- this.fireItemsReplaced(event.cloneWithSource(this, LIST_VALUES, this.prefix.size()));
- }
-
- @Override
- protected void itemsMoved(ListChangeEvent event) {
- this.fireItemsMoved(event.cloneWithSource(this, LIST_VALUES, this.prefix.size()));
- }
-
- @Override
- protected void listCleared(ListChangeEvent event) {
- this.fireListChanged(LIST_VALUES); // not "cleared"
- }
-
- @Override
- protected void listChanged(ListChangeEvent event) {
- this.fireListChanged(LIST_VALUES);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.prefix);
- sb.append(" ");
- super.toString(sb);
- sb.append(" ");
- sb.append(this.suffix);
- }
-
-
- // ********** miscellaneous **********
-
- public void setPrefix(List<E> prefix) {
- this.prefix = prefix;
- this.fireListChanged(LIST_VALUES);
- }
-
- public void setSuffix(List<E> suffix) {
- this.suffix = suffix;
- this.fireListChanged(LIST_VALUES);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java
deleted file mode 100644
index 8dc865a0f3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringCollectionValueModel.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.Filter;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.FilteringIterator;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * A <code>FilteringCollectionValueModel</code> wraps another
- * <code>CollectionValueModel</code> and uses a <code>Filter</code>
- * to determine which items in the collection are returned by calls
- * to <code>#iterator()</code>.
- * <p>
- * The filter can be changed at any time; allowing the same
- * adapter to be used with different filter criteria (e.g. when the user
- * wants to view a list of .java files).
- * <p>
- * NB: If the objects in the "filtered" collection can change in such a way
- * that they should be removed from the "filtered" collection, you will
- * need to wrap the original collection in an ItemAspectListValueModelAdapter.
- * For example, if the filter only "accepts" items whose names begin
- * with "X" and the names of the items can change, you will need to
- * wrap the original list of unfiltered items with an
- * ItemPropertyListValueModelAdapter that listens for changes to each
- * item's name and fires the appropriate event whenever an item's name
- * changes. The event will cause this wrapper to re-filter the changed
- * item and add or remove it from the "filtered" collection as appropriate.
- */
-public class FilteringCollectionValueModel<E>
- extends CollectionValueModelWrapper<E>
- implements CollectionValueModel<E>
-{
- /** This filters the items in the nested collection. */
- private Filter<E> filter;
-
- /** Cache the items that were accepted by the filter */
- private final Collection<E> filteredItems;
-
-
- // ********** constructors **********
-
- /**
- * Construct a collection value model with the specified wrapped
- * collection value model and a filter that simply accepts every object.
- */
- public FilteringCollectionValueModel(CollectionValueModel<? extends E> collectionHolder) {
- this(collectionHolder, Filter.Null.<E>instance());
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * collection value model and filter.
- */
- public FilteringCollectionValueModel(CollectionValueModel<? extends E> collectionHolder, Filter<E> filter) {
- super(collectionHolder);
- this.filter = filter;
- this.filteredItems = new ArrayList<E>();
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * list value model and a filter that simply accepts every object.
- */
- public FilteringCollectionValueModel(ListValueModel<E> listHolder) {
- this(new ListCollectionValueModelAdapter<E>(listHolder));
- }
-
- /**
- * Construct a collection value model with the specified wrapped
- * list value model and filter.
- */
- public FilteringCollectionValueModel(ListValueModel<E> listHolder, Filter<E> filter) {
- this(new ListCollectionValueModelAdapter<E>(listHolder), filter);
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- public Iterator<E> iterator() {
- return new ReadOnlyIterator<E>(this.filteredItems);
- }
-
- public int size() {
- return this.filteredItems.size();
- }
-
-
- // ********** CollectionValueModelWrapper overrides/implementation **********
-
- @Override
- protected void engageModel() {
- super.engageModel();
- // synch our cache *after* we start listening to the nested collection,
- // since its value might change when a listener is added
- CollectionTools.addAll(this.filteredItems, this.filter(this.collectionHolder.iterator()));
- }
-
- @Override
- protected void disengageModel() {
- super.disengageModel();
- // clear out the cache when we are not listening to the nested collection
- this.filteredItems.clear();
- }
-
- @Override
- protected void itemsAdded(CollectionChangeEvent event) {
- // filter the values before propagating the change event
- this.addItemsToCollection(this.filter(this.items(event)), this.filteredItems, VALUES);
- }
-
- @Override
- protected void itemsRemoved(CollectionChangeEvent event) {
- // do *not* filter the values, because they may no longer be
- // "accepted" and that might be why they were removed in the first place;
- // anyway, any extraneous items are harmless
- this.removeItemsFromCollection(event.items(), this.filteredItems, VALUES);
- }
-
- @Override
- protected void collectionCleared(CollectionChangeEvent event) {
- this.clearCollection(this.filteredItems, VALUES);
- }
-
- @Override
- protected void collectionChanged(CollectionChangeEvent event) {
- this.rebuildFilteredItems();
- }
-
-
- // ********** miscellaneous **********
-
- /**
- * Change the filter and rebuild the collection.
- */
- public void setFilter(Filter<E> filter) {
- this.filter = filter;
- this.rebuildFilteredItems();
- }
-
- /**
- * Return an iterator that filters the specified iterator.
- */
- protected Iterator<E> filter(Iterator<? extends E> items) {
- return new FilteringIterator<E, E>(items, this.filter);
- }
-
- /**
- * Synchronize our cache with the wrapped collection.
- */
- protected void rebuildFilteredItems() {
- this.filteredItems.clear();
- CollectionTools.addAll(this.filteredItems, this.filter(this.collectionHolder.iterator()));
- this.fireCollectionChanged(VALUES);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java
deleted file mode 100644
index a56cc34c80..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringPropertyValueModel.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.Filter;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * A <code>FilteringPropertyValueModel</code> wraps another
- * <code>PropertyValueModel</code> and uses a <code>Filter</code>
- * to determine when the wrapped value is to be returned by calls
- * to <code>value()</code>.
- * <p>
- * As an alternative to building a <code>Filter</code>, a subclass
- * of <code>FilteringPropertyValueModel</code> can override the
- * <code>accept(Object)</code> method.
- * <p>
- * One, possibly undesirable, side-effect of using this value model is that
- * it must return *something* as the value. The default behavior is
- * to return <code>null</code> whenever the wrapped value is not "accepted",
- * which can be configured and/or overridden.
- */
-public class FilteringPropertyValueModel<T>
- extends PropertyValueModelWrapper<T>
- implements PropertyValueModel<T>
-{
- protected final Filter<T> filter;
- protected final T defaultValue;
-
-
- // ********** constructors **********
-
- /**
- * Construct a property value model with the specified nested
- * property value model and a disabled filter.
- * Use this constructor if you want to override the
- * <code>accept(Object)</code>
- * method instead of building a <code>Filter</code>.
- * The default value will be <code>null</code>.
- */
- public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder) {
- this(valueHolder, Filter.Disabled.<T>instance(), null);
- }
-
- /**
- * Construct a property value model with the specified nested
- * property value model, specified default value, and a disabled filter.
- * Use this constructor if you want to override the
- * <code>accept(Object)</code>
- * method instead of building a <code>Filter</code>
- * <em>and</em> you need to specify
- * a default value other than <code>null</code>.
- */
- public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder, T defaultValue) {
- this(valueHolder, Filter.Disabled.<T>instance(), defaultValue);
- }
-
- /**
- * Construct an property value model with the specified nested
- * property value model and filter.
- * The default value will be <code>null</code>.
- */
- public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder, Filter<T> filter) {
- this(valueHolder, filter, null);
- }
-
- /**
- * Construct an property value model with the specified nested
- * property value model, filter, and default value.
- */
- public FilteringPropertyValueModel(PropertyValueModel<? extends T> valueHolder, Filter<T> filter, T defaultValue) {
- super(valueHolder);
- this.filter = filter;
- this.defaultValue = defaultValue;
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- public T getValue() {
- return this.filterValue(this.valueHolder.getValue());
- }
-
-
- // ********** PropertyValueModelWrapper implementation **********
-
- @Override
- protected void valueChanged(PropertyChangeEvent event) {
- // filter the values before propagating the change event
- @SuppressWarnings("unchecked")
- Object oldValue = this.filterValue((T) event.getOldValue());
- @SuppressWarnings("unchecked")
- Object newValue = this.filterValue((T) event.getNewValue());
- this.firePropertyChanged(VALUE, oldValue, newValue);
- }
-
-
- // ********** queries **********
-
- /**
- * If the specified value is "accepted" simply return it,
- * otherwise return the default value.
- */
- protected T filterValue(T value) {
- return this.accept(value) ? value : this.defaultValue();
- }
-
- /**
- * Return whether the <code>FilteringPropertyValueModel</code> should
- * return the specified value from a call to the
- * <code>value()</code> method; the value came
- * from the nested property value model
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>Filter</code>.
- */
- protected boolean accept(T value) {
- return this.filter.accept(value);
- }
-
- /**
- * Return the object that should be returned if
- * the nested value was rejected by the filter.
- * The default is <code>null</code>.
- */
- protected T defaultValue() {
- return this.defaultValue;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java
deleted file mode 100644
index d7e20f4cb3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/FilteringWritablePropertyValueModel.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.BidiFilter;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * A <code>FilteringWritablePropertyValueModel</code> wraps another
- * <code>WritabelPropertyValueModel</code> and uses a <code>BidiFilter</code>
- * to determine when the wrapped value is to be returned by calls
- * to <code>value()</code> and modified by calls to
- * <code>setValue(Object)</code>.
- * <p>
- * As an alternative to building a <code>BidiFilter</code>, a subclass
- * of <code>FilteringWritablePropertyValueModel</code> can override the
- * <code>accept(Object)</code> and <code>reverseAccept(Object)</code>
- * methods.
- * <p>
- * One, possibly undesirable, side-effect of using this value model is that
- * it must return *something* as the value. The default behavior is
- * to return <code>null</code> whenever the wrapped value is not "accepted",
- * which can be configured and/or overridden.
- * <p>
- * Similarly, if an incoming value is not "reverseAccepted", *nothing* will passed
- * through to the wrapped value holder, not even <code>null</code>.
- */
-public class FilteringWritablePropertyValueModel<T>
- extends FilteringPropertyValueModel<T>
- implements WritablePropertyValueModel<T>
-{
-
-
- // ********** constructors **********
-
- /**
- * Construct a property value model with the specified nested
- * property value model and a disabled filter.
- * Use this constructor if you want to override the
- * <code>accept(Object)</code> and <code>reverseAccept(Object)</code>
- * methods instead of building a <code>BidiFilter</code>.
- * The default value will be <code>null</code>.
- */
- public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder) {
- this(valueHolder, BidiFilter.Disabled.<T>instance(), null);
- }
-
- /**
- * Construct a property value model with the specified nested
- * property value model, specified default value, and a disabled filter.
- * Use this constructor if you want to override the
- * <code>accept(Object)</code> and <code>reverseAccept(Object)</code>
- * methods instead of building a <code>BidiFilter</code>
- * <em>and</em> you need to specify
- * a default value other than <code>null</code>.
- */
- public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, T defaultValue) {
- this(valueHolder, BidiFilter.Disabled.<T>instance(), defaultValue);
- }
-
- /**
- * Construct an property value model with the specified nested
- * property value model and filter.
- * The default value will be <code>null</code>.
- */
- public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, BidiFilter<T> filter) {
- this(valueHolder, filter, null);
- }
-
- /**
- * Construct an property value model with the specified nested
- * property value model, filter, and default value.
- */
- public FilteringWritablePropertyValueModel(WritablePropertyValueModel<T> valueHolder, BidiFilter<T> filter, T defaultValue) {
- super(valueHolder, filter, defaultValue);
- }
-
-
- // ********** WritablePropertyValueModel implementation **********
-
- public void setValue(T value) {
- if (this.reverseAccept(value)) {
- this.valueHolder().setValue(value);
- }
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether the <code>FilteringWritablePropertyValueModel</code>
- * should pass through the specified value to the nested
- * writable property value model in a call to the
- * <code>setValue(Object)</code> method
- * <p>
- * This method can be overridden by a subclass as an
- * alternative to building a <code>BidiFilter</code>.
- */
- protected boolean reverseAccept(T value) {
- return this.getFilter().reverseAccept(value);
- }
-
- /**
- * Our constructors accept only a WritablePropertyValueModel<T>.
- */
- @SuppressWarnings("unchecked")
- protected WritablePropertyValueModel<T> valueHolder() {
- return (WritablePropertyValueModel<T>) this.valueHolder;
- }
-
- /**
- * Our constructors accept only a bidirectional filter.
- */
- protected BidiFilter<T> getFilter() {
- return (BidiFilter<T>) this.filter;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java
deleted file mode 100644
index 17538f93d3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemAspectListValueModelAdapter.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EventObject;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.Counter;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Abstract list value model that provides behavior for wrapping a list value
- * model (or collection value model) and listening for changes to aspects of the
- * *items* held by the list (or collection). Changes to the actual list
- * (or collection) are also monitored.
- *
- * This is useful if you have a collection of items that can be modified by adding
- * or removing items or the items themselves might change in a fashion that
- * might change the collection's external appearance.
- *
- * Subclasses need to override two methods:
- *
- * #listenToItem(Model)
- * begin listening to the appropriate aspect of the specified item and call
- * #itemAspectChanged(Object) whenever the aspect changes
- *
- * #stopListeningToItem(Model)
- * stop listening to the appropriate aspect of the specified item
- */
-public abstract class ItemAspectListValueModelAdapter<E>
- extends ListValueModelWrapper<E>
- implements ListValueModel<E>
-{
-
- /**
- * Maintain a counter for each of the items in the
- * wrapped list holder we are listening to.
- */
- protected final IdentityHashMap<E, Counter> counters;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the list holder is required.
- */
- protected ItemAspectListValueModelAdapter(ListValueModel<? extends E> listHolder) {
- super(listHolder);
- this.counters = new IdentityHashMap<E, Counter>();
- }
-
- /**
- * Constructor - the collection holder is required.
- */
- protected ItemAspectListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder));
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E> listIterator() {
- return new ReadOnlyListIterator<E>(this.listHolder.listIterator());
- }
-
- public E get(int index) {
- return this.listHolder.get(index);
- }
-
- public int size() {
- return this.listHolder.size();
- }
-
- public Object[] toArray() {
- return this.listHolder.toArray();
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the list holder and the items in the list.
- */
- @Override
- protected void engageModel() {
- super.engageModel();
- this.engageAllItems();
- }
-
- protected void engageAllItems() {
- this.engageItems(this.listHolder.iterator());
- }
-
- protected void engageItems(Iterator<? extends E> stream) {
- while (stream.hasNext()) {
- this.engageItem(stream.next());
- }
- }
-
- protected void engageItem(E item) {
- // listen to an item only once
- Counter counter = this.counters.get(item);
- if (counter == null) {
- counter = new Counter();
- this.counters.put(item, counter);
- this.startListeningToItem((Model) item);
- }
- counter.increment();
- }
-
- /**
- * Start listening to the specified item.
- */
- protected abstract void startListeningToItem(Model item);
-
- /**
- * Stop listening to the list holder and the items in the list.
- */
- @Override
- protected void disengageModel() {
- this.disengageAllItems();
- super.disengageModel();
- }
-
- protected void disengageAllItems() {
- this.disengageItems(this.listHolder.iterator());
- }
-
- protected void disengageItems(Iterator<? extends E> stream) {
- while (stream.hasNext()) {
- this.disengageItem(stream.next());
- }
- }
-
- protected void disengageItem(E item) {
- // stop listening to an item only once
- Counter counter = this.counters.get(item);
- if (counter == null) {
- // something is wrong if this happens... ~bjv
- throw new IllegalStateException("missing counter: " + item);
- }
- if (counter.decrement() == 0) {
- this.counters.remove(item);
- this.stopListeningToItem((Model) item);
- }
- }
-
- /**
- * Stop listening to the specified item.
- */
- protected abstract void stopListeningToItem(Model item);
-
-
- // ********** list change support **********
-
- /**
- * Items were added to the wrapped list holder.
- * Forward the event and begin listening to the added items.
- */
- @Override
- protected void itemsAdded(ListChangeEvent event) {
- // re-fire event with the wrapper as the source
- this.fireItemsAdded(event.cloneWithSource(this, LIST_VALUES));
- this.engageItems(this.items(event));
- }
-
- /**
- * Items were removed from the wrapped list holder.
- * Stop listening to the removed items and forward the event.
- */
- @Override
- protected void itemsRemoved(ListChangeEvent event) {
- this.disengageItems(this.items(event));
- // re-fire event with the wrapper as the source
- this.fireItemsRemoved(event.cloneWithSource(this, LIST_VALUES));
- }
-
- /**
- * Items were replaced in the wrapped list holder.
- * Stop listening to the removed items, forward the event,
- * and begin listening to the added items.
- */
- @Override
- protected void itemsReplaced(ListChangeEvent event) {
- this.disengageItems(this.replacedItems(event));
- // re-fire event with the wrapper as the source
- this.fireItemsReplaced(event.cloneWithSource(this, LIST_VALUES));
- this.engageItems(this.items(event));
- }
-
- /**
- * Items were moved in the wrapped list holder.
- * No need to change any listeners; just forward the event.
- */
- @Override
- protected void itemsMoved(ListChangeEvent event) {
- // re-fire event with the wrapper as the source
- this.fireItemsMoved(event.cloneWithSource(this, LIST_VALUES));
- }
-
- /**
- * The wrapped list holder was cleared.
- * Stop listening to the removed items and forward the event.
- */
- @Override
- protected void listCleared(ListChangeEvent event) {
- // we should only need to disengage each item once...
- // make a copy to prevent a ConcurrentModificationException
- Collection<E> keys = new ArrayList<E>(this.counters.keySet());
- this.disengageItems(keys.iterator());
- this.counters.clear();
- // re-fire event with the wrapper as the source
- this.fireListCleared(LIST_VALUES);
- }
-
- /**
- * The wrapped list holder has changed in some dramatic fashion.
- * Reconfigure our listeners and forward the event.
- */
- @Override
- protected void listChanged(ListChangeEvent event) {
- // we should only need to disengage each item once...
- // make a copy to prevent a ConcurrentModificationException
- Collection<E> keys = new ArrayList<E>(this.counters.keySet());
- this.disengageItems(keys.iterator());
- this.counters.clear();
- // re-fire event with the wrapper as the source
- this.fireListChanged(LIST_VALUES);
- this.engageAllItems();
- }
-
-
- // ********** item change support **********
-
- /**
- * The specified item has a bound property that has changed.
- * Notify listeners of the change.
- */
- protected void itemAspectChanged(EventObject event) {
- Object item = event.getSource();
- int index = this.lastIdentityIndexOf(item);
- while (index != -1) {
- this.itemAspectChanged(index, item);
- index = this.lastIdentityIndexOf(item, index);
- }
- }
-
- /**
- * The specified item has a bound property that has changed.
- * Notify listeners of the change.
- */
- protected void itemAspectChanged(int index, Object item) {
- this.fireItemReplaced(LIST_VALUES, index, item, item); // hmmm...
- }
-
- /**
- * Return the last index of the specified item, using object
- * identity instead of equality.
- */
- protected int lastIdentityIndexOf(Object o) {
- return this.lastIdentityIndexOf(o, this.listHolder.size());
- }
-
- /**
- * Return the last index of the specified item, starting just before the
- * the specified endpoint, and using object identity instead of equality.
- */
- protected int lastIdentityIndexOf(Object o, int end) {
- for (int i = end; i-- > 0; ) {
- if (this.listHolder.get(i) == o) {
- return i;
- }
- }
- return -1;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java
deleted file mode 100644
index 151a90f6c3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemCollectionListValueModelAdapter.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Extend ItemAspectListValueModelAdapter to listen to one or more collection
- * aspects of each item in the wrapped list model.
- */
-public class ItemCollectionListValueModelAdapter<E>
- extends ItemAspectListValueModelAdapter<E>
-{
-
- /** The names of the items' collections that we listen to. */
- protected final String[] collectionNames;
-
- /** Listener that listens to all the items in the list. */
- protected final CollectionChangeListener itemCollectionListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified item Collections.
- */
- public ItemCollectionListValueModelAdapter(ListValueModel<E> listHolder, String... collectionNames) {
- super(listHolder);
- this.collectionNames = collectionNames;
- this.itemCollectionListener = this.buildItemCollectionListener();
- }
-
- /**
- * Construct an adapter for the specified item Collections.
- */
- public ItemCollectionListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... collectionNames) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder), collectionNames);
- }
-
-
- // ********** initialization **********
-
- /**
- * All we really care about is the fact that a Collection aspect has
- * changed. Do the same thing no matter which event occurs.
- */
- protected CollectionChangeListener buildItemCollectionListener() {
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- ItemCollectionListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- ItemCollectionListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void collectionCleared(CollectionChangeEvent event) {
- ItemCollectionListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void collectionChanged(CollectionChangeEvent event) {
- ItemCollectionListValueModelAdapter.this.itemAspectChanged(event);
- }
- @Override
- public String toString() {
- return "item collection listener: " + Arrays.asList(ItemCollectionListValueModelAdapter.this.collectionNames);
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void startListeningToItem(Model item) {
- for (String collectionName : this.collectionNames) {
- item.addCollectionChangeListener(collectionName, this.itemCollectionListener);
- }
- }
-
- @Override
- protected void stopListeningToItem(Model item) {
- for (String collectionName : this.collectionNames) {
- item.removeCollectionChangeListener(collectionName, this.itemCollectionListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java
deleted file mode 100644
index 5354c1bde5..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemListListValueModelAdapter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Extend ItemAspectListValueModelAdapter to listen to one or more list
- * aspects of each item in the wrapped list model.
- */
-public class ItemListListValueModelAdapter<E>
- extends ItemAspectListValueModelAdapter<E>
-{
-
- /** The names of the subject's lists that we listen to. */
- protected final String[] listNames;
-
- /** Listener that listens to all the items in the list. */
- protected final ListChangeListener itemListListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified item List aspects.
- */
- public ItemListListValueModelAdapter(ListValueModel<E> listHolder, String... listNames) {
- super(listHolder);
- this.listNames = listNames;
- this.itemListListener = this.buildItemListListener();
- }
-
- /**
- * Construct an adapter for the specified item List aspects.
- */
- public ItemListListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... listNames) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder), listNames);
- }
-
-
- // ********** initialization **********
-
- /**
- * All we really care about is the fact that the List aspect has
- * changed. Do the same thing no matter which event occurs.
- */
- protected ListChangeListener buildItemListListener() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ItemListListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- ItemListListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- ItemListListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- ItemListListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void listCleared(ListChangeEvent event) {
- ItemListListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void listChanged(ListChangeEvent event) {
- ItemListListValueModelAdapter.this.itemAspectChanged(event);
- }
- @Override
- public String toString() {
- return "item list listener: " + Arrays.asList(ItemListListValueModelAdapter.this.listNames);
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void startListeningToItem(Model item) {
- for (String listName : this.listNames) {
- item.addListChangeListener(listName, this.itemListListener);
- }
- }
-
- @Override
- protected void stopListeningToItem(Model item) {
- for (String listName : this.listNames) {
- item.removeListChangeListener(listName, this.itemListListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java
deleted file mode 100644
index 48140a0c5b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemPropertyListValueModelAdapter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Extend ItemAspectListValueModelAdapter to listen to one or more
- * properties of each item in the wrapped list model.
- */
-public class ItemPropertyListValueModelAdapter<E>
- extends ItemAspectListValueModelAdapter<E>
-{
-
- /** The names of the items' properties that we listen to. */
- protected final String[] propertyNames;
-
- /** Listener that listens to all the items in the list. */
- protected final PropertyChangeListener itemPropertyListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified item properties.
- */
- public ItemPropertyListValueModelAdapter(ListValueModel<E> listHolder, String... propertyNames) {
- super(listHolder);
- this.propertyNames = propertyNames;
- this.itemPropertyListener = this.buildItemPropertyListener();
- }
-
- /**
- * Construct an adapter for the specified item properties.
- */
- public ItemPropertyListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... propertyNames) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder), propertyNames);
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildItemPropertyListener() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- ItemPropertyListValueModelAdapter.this.itemAspectChanged(event);
- }
- @Override
- public String toString() {
- return "item property listener: " + Arrays.asList(ItemPropertyListValueModelAdapter.this.propertyNames);
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void startListeningToItem(Model item) {
- for (String propertyName : this.propertyNames) {
- item.addPropertyChangeListener(propertyName, this.itemPropertyListener);
- }
- }
-
- @Override
- protected void stopListeningToItem(Model item) {
- for (String propertyName : this.propertyNames) {
- item.removePropertyChangeListener(propertyName, this.itemPropertyListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java
deleted file mode 100644
index 46d7d863fb..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemStateListValueModelAdapter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Extend ItemAspectListValueModelAdapter to listen to the
- * "state" of each item in the wrapped list model.
- */
-public class ItemStateListValueModelAdapter<E>
- extends ItemAspectListValueModelAdapter<E>
-{
- /** Listener that listens to all the items in the list. */
- protected final StateChangeListener itemStateListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the item state.
- */
- public ItemStateListValueModelAdapter(ListValueModel<E> listHolder) {
- super(listHolder);
- this.itemStateListener = this.buildItemStateListener();
- }
-
- /**
- * Construct an adapter for the item state.
- */
- public ItemStateListValueModelAdapter(CollectionValueModel<E> collectionHolder) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder));
- }
-
-
- // ********** initialization **********
-
- protected StateChangeListener buildItemStateListener() {
- return new StateChangeListener() {
- public void stateChanged(StateChangeEvent event) {
- ItemStateListValueModelAdapter.this.itemAspectChanged(event);
- }
- @Override
- public String toString() {
- return "item state listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void startListeningToItem(Model item) {
- item.addStateChangeListener(this.itemStateListener);
- }
-
- @Override
- protected void stopListeningToItem(Model item) {
- item.removeStateChangeListener(this.itemStateListener);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java
deleted file mode 100644
index 4e39f6ec34..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ItemTreeListValueModelAdapter.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Extend ItemAspectListValueModelAdapter to listen to one or more tree
- * aspects of each item in the wrapped list model.
- */
-public class ItemTreeListValueModelAdapter<E>
- extends ItemAspectListValueModelAdapter<E>
-{
-
- /** The names of the items' tree that we listen to. */
- protected final String[] treeNames;
-
- /** Listener that listens to all the items in the list. */
- protected final TreeChangeListener itemTreeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified item trees.
- */
- public ItemTreeListValueModelAdapter(ListValueModel<E> listHolder, String... treeNames) {
- super(listHolder);
- this.treeNames = treeNames;
- this.itemTreeListener = this.buildItemTreeListener();
- }
-
- /**
- * Construct an adapter for the specified item trees.
- */
- public ItemTreeListValueModelAdapter(CollectionValueModel<E> collectionHolder, String... treeNames) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder), treeNames);
- }
-
-
- // ********** initialization **********
-
- /**
- * All we really care about is the fact that a tree aspect has
- * changed. Do the same thing no matter which event occurs.
- */
- protected TreeChangeListener buildItemTreeListener() {
- return new TreeChangeListener() {
- public void nodeAdded(TreeChangeEvent event) {
- ItemTreeListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void nodeRemoved(TreeChangeEvent event) {
- ItemTreeListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void treeCleared(TreeChangeEvent event) {
- ItemTreeListValueModelAdapter.this.itemAspectChanged(event);
- }
- public void treeChanged(TreeChangeEvent event) {
- ItemTreeListValueModelAdapter.this.itemAspectChanged(event);
- }
- @Override
- public String toString() {
- return "item tree listener: " + Arrays.asList(ItemTreeListValueModelAdapter.this.treeNames);
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void startListeningToItem(Model item) {
- for (String treeName : this.treeNames) {
- item.addTreeChangeListener(treeName, this.itemTreeListener);
- }
- }
-
- @Override
- protected void stopListeningToItem(Model item) {
- for (String treeName : this.treeNames) {
- item.removeTreeChangeListener(treeName, this.itemTreeListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java
deleted file mode 100644
index b8adaaa96f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListAspectAdapter.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This extension of AspectAdapter provides ListChange support.
- * This allows us to convert a set of one or more collections into
- * a single collection, LIST_VALUES.
- *
- * The typical subclass will override the following methods:
- * #listIterator_()
- * at the very minimum, override this method to return a list iterator
- * on the subject's list aspect; it does not need to be overridden if
- * #listIterator() is overridden and its behavior changed
- * #get(int)
- * override this method to improve performance
- * #size_()
- * override this method to improve performance; it does not need to be overridden if
- * #size() is overridden and its behavior changed
- * #listIterator()
- * override this method only if returning an empty list iterator when the
- * subject is null is unacceptable
- * #size()
- * override this method only if returning a zero when the
- * subject is null is unacceptable
- */
-public abstract class ListAspectAdapter<S extends Model, E>
- extends AspectAdapter<S>
- implements ListValueModel<E>
-{
- /**
- * The name of the subject's lists that we use for the value.
- */
- protected final String[] listNames;
- protected static final String[] EMPTY_LIST_NAMES = new String[0];
-
- /** A listener that listens to the subject's list aspect. */
- protected final ListChangeListener listChangeListener;
-
- private static final Object[] EMPTY_ARRAY = new Object[0];
-
-
- // ********** constructors **********
-
- /**
- * Construct a ListAspectAdapter for the specified subject
- * and list.
- */
- protected ListAspectAdapter(String listName, S subject) {
- this(new String[] {listName}, subject);
- }
-
- /**
- * Construct a ListAspectAdapter for the specified subject
- * and lists.
- */
- protected ListAspectAdapter(String[] listNames, S subject) {
- this(new StaticPropertyValueModel<S>(subject), listNames);
- }
-
- /**
- * Construct a ListAspectAdapter for the specified subject holder
- * and lists.
- */
- protected ListAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... listNames) {
- super(subjectHolder);
- this.listNames = listNames;
- this.listChangeListener = this.buildListChangeListener();
- }
-
- /**
- * Construct a ListAspectAdapter for the specified subject holder
- * and lists.
- */
- protected ListAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> listNames) {
- this(subjectHolder, listNames.toArray(new String[listNames.size()]));
- }
-
- /**
- * Construct a ListAspectAdapter for an "unchanging" list in
- * the specified subject. This is useful for a list aspect that does not
- * change for a particular subject; but the subject will change, resulting in
- * a new list.
- */
- protected ListAspectAdapter(PropertyValueModel<? extends S> subjectHolder) {
- this(subjectHolder, EMPTY_LIST_NAMES);
- }
-
-
- // ********** initialization **********
-
- /**
- * The subject's list aspect has changed, notify the listeners.
- */
- protected ListChangeListener buildListChangeListener() {
- // transform the subject's list change events into VALUE list change events
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ListAspectAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- ListAspectAdapter.this.itemsRemoved(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- ListAspectAdapter.this.itemsReplaced(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- ListAspectAdapter.this.itemsMoved(event);
- }
- public void listCleared(ListChangeEvent event) {
- ListAspectAdapter.this.listCleared(event);
- }
- public void listChanged(ListChangeEvent event) {
- ListAspectAdapter.this.listChanged(event);
- }
- @Override
- public String toString() {
- return "list change listener: " + Arrays.asList(ListAspectAdapter.this.listNames);
- }
- };
- }
-
-
- // ********** ListValueModel implementation **********
-
- /**
- * Return the elements of the subject's list aspect.
- */
- public Iterator<E> iterator() {
- return this.listIterator();
- }
-
- /**
- * Return the elements of the subject's list aspect.
- */
- public ListIterator<E> listIterator() {
- return (this.subject == null) ? EmptyListIterator.<E>instance() : this.listIterator_();
- }
-
- /**
- * Return the elements of the subject's list aspect.
- * At this point we can be sure that the subject is not null.
- * @see #listIterator()
- */
- protected ListIterator<E> listIterator_() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Return the element at the specified index of the subject's list aspect.
- */
- public E get(int index) {
- return CollectionTools.get(this.listIterator(), index);
- }
-
- /**
- * Return the size of the subject's list aspect.
- */
- public int size() {
- return this.subject == null ? 0 : this.size_();
- }
-
- /**
- * Return the size of the subject's list aspect.
- * At this point we can be sure that the subject is not null.
- * @see #size()
- */
- protected int size_() {
- return CollectionTools.size(this.listIterator());
- }
-
- /**
- * Return an array manifestation of the subject's list aspect.
- */
- public Object[] toArray() {
- return this.subject == null ? EMPTY_ARRAY : this.toArray_();
- }
-
- /**
- * Return an array manifestation of the subject's list aspect.
- * At this point we can be sure that the subject is not null.
- * @see #toArray()
- */
- protected Object[] toArray_() {
- return CollectionTools.array(this.listIterator(), this.size());
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Object getValue() {
- return this.iterator();
- }
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return ListChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return LIST_VALUES;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyListChangeListeners(LIST_VALUES);
- }
-
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.fireListChanged(LIST_VALUES);
- }
-
- @Override
- protected void engageSubject_() {
- for (String listName : this.listNames) {
- ((Model) this.subject).addListChangeListener(listName, this.listChangeListener);
- }
- }
-
- @Override
- protected void disengageSubject_() {
- for (String listName : this.listNames) {
- ((Model) this.subject).removeListChangeListener(listName, this.listChangeListener);
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- for (int i = 0; i < this.listNames.length; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(this.listNames[i]);
- }
- }
-
-
- // ********** behavior **********
-
- protected void itemsAdded(ListChangeEvent event) {
- this.fireItemsAdded(event.cloneWithSource(this, LIST_VALUES));
- }
-
- protected void itemsRemoved(ListChangeEvent event) {
- this.fireItemsRemoved(event.cloneWithSource(this, LIST_VALUES));
- }
-
- protected void itemsReplaced(ListChangeEvent event) {
- this.fireItemsReplaced(event.cloneWithSource(this, LIST_VALUES));
- }
-
- protected void itemsMoved(ListChangeEvent event) {
- this.fireItemsMoved(event.cloneWithSource(this, LIST_VALUES));
- }
-
- protected void listCleared(ListChangeEvent event) {
- this.fireListCleared(LIST_VALUES); // nothing from original event to forward
- }
-
- protected void listChanged(ListChangeEvent event) {
- this.fireListChanged(LIST_VALUES); // nothing from original event to forward
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java
deleted file mode 100644
index dc8a7aad40..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCollectionValueModelAdapter.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * An adapter that allows us to make a ListValueModel behave like
- * a read-only CollectionValueModel, sorta.
- *
- * We keep an internal collection somewhat in synch with the wrapped list.
- *
- * NB: Since we only listen to the wrapped list when we have
- * listeners ourselves and we can only stay in synch with the wrapped
- * list while we are listening to it, results to various methods
- * (e.g. #size(), value()) will be unpredictable whenever
- * we do not have any listeners. This should not be too painful since,
- * most likely, client objects will also be listeners.
- */
-public class ListCollectionValueModelAdapter<E>
- extends AbstractModel
- implements CollectionValueModel<E>
-{
- /** The wrapped list value model. */
- protected final ListValueModel<? extends E> listHolder;
-
- /** A listener that forwards any events fired by the list holder. */
- protected final ListChangeListener listChangeListener;
-
- /**
- * Our internal collection, which holds the same elements as
- * the wrapped list.
- */
- // we declare this an ArrayList so we can use #clone() and #ensureCapacity(int)
- protected final ArrayList<E> collection;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Wrap the specified ListValueModel.
- */
- public ListCollectionValueModelAdapter(ListValueModel<? extends E> listHolder) {
- super();
- if (listHolder == null) {
- throw new NullPointerException();
- }
- this.listHolder = listHolder;
- this.listChangeListener = this.buildListChangeListener();
- this.collection = new ArrayList<E>();
- // postpone building the collection and listening to the underlying list
- // until we have listeners ourselves...
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, CollectionChangeListener.class, VALUES);
- }
-
- /**
- * The wrapped list has changed, forward an equivalent
- * collection change event to our listeners.
- */
- protected ListChangeListener buildListChangeListener() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ListCollectionValueModelAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- ListCollectionValueModelAdapter.this.itemsRemoved(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- ListCollectionValueModelAdapter.this.itemsReplaced(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- ListCollectionValueModelAdapter.this.itemsMoved(event);
- }
- public void listCleared(ListChangeEvent event) {
- ListCollectionValueModelAdapter.this.listCleared(event);
- }
- public void listChanged(ListChangeEvent event) {
- ListCollectionValueModelAdapter.this.listChanged(event);
- }
- @Override
- public String toString() {
- return "list change listener";
- }
- };
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- public Iterator<E> iterator() {
- // try to prevent backdoor modification of the list
- return new ReadOnlyIterator<E>(this.collection);
- }
-
- public int size() {
- return this.collection.size();
- }
-
-
- // ********** extend change support **********
-
- /**
- * Override to start listening to the list holder if necessary.
- */
- @Override
- public void addCollectionChangeListener(CollectionChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addCollectionChangeListener(listener);
- }
-
- /**
- * Override to start listening to the list holder if necessary.
- */
- @Override
- public void addCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- if (collectionName == VALUES && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addCollectionChangeListener(collectionName, listener);
- }
-
- /**
- * Override to stop listening to the list holder if appropriate.
- */
- @Override
- public void removeCollectionChangeListener(CollectionChangeListener listener) {
- super.removeCollectionChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Override to stop listening to the list holder if appropriate.
- */
- @Override
- public void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- super.removeCollectionChangeListener(collectionName, listener);
- if (collectionName == VALUES && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** queries **********
-
- protected boolean hasListeners() {
- return this.hasAnyCollectionChangeListeners(VALUES);
- }
-
- protected boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
- /**
- * Return the index of the specified item, using object
- * identity instead of equality.
- */
- protected int lastIdentityIndexOf(Object o) {
- return this.lastIdentityIndexOf(o, this.collection.size());
- }
-
- /**
- * Return the last index of the specified item, starting just before the
- * the specified endpoint, and using object identity instead of equality.
- */
- protected int lastIdentityIndexOf(Object o, int end) {
- for (int i = end; i-- > 0; ) {
- if (this.collection.get(i) == o) {
- return i;
- }
- }
- return -1;
- }
-
-
- // ********** behavior **********
-
- protected void buildCollection() {
- Iterator<? extends E> stream = this.listHolder.iterator();
- // if the new list is empty, do nothing
- if (stream.hasNext()) {
- this.collection.ensureCapacity(this.listHolder.size());
- while (stream.hasNext()) {
- this.collection.add(stream.next());
- }
- }
- }
-
- protected void engageModel() {
- this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- // synch our collection *after* we start listening to the list holder,
- // since its value might change when a listener is added
- this.buildCollection();
- }
-
- protected void disengageModel() {
- this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- // clear out the collection when we are not listening to the list holder
- this.collection.clear();
- }
-
- // minimize suppressed warnings
- @SuppressWarnings("unchecked")
- protected ListIterator<E> items(ListChangeEvent event) {
- return (ListIterator<E>) event.items();
- }
-
- // minimize suppressed warnings
- @SuppressWarnings("unchecked")
- protected ListIterator<E> replacedItems(ListChangeEvent event) {
- return (ListIterator<E>) event.replacedItems();
- }
-
- protected void itemsAdded(ListChangeEvent event) {
- this.addItemsToCollection(this.items(event), this.collection, VALUES);
- }
-
- protected void removeInternalItems(Iterator<E> items) {
- // we have to remove the items individually,
- // since they are probably not in sequence
- while (items.hasNext()) {
- Object removedItem = items.next();
- int index = this.lastIdentityIndexOf(removedItem);
- this.collection.remove(index);
- this.fireItemRemoved(VALUES, removedItem);
- }
- }
-
- protected void itemsRemoved(ListChangeEvent event) {
- this.removeInternalItems(this.items(event));
- }
-
- protected void itemsReplaced(ListChangeEvent event) {
- this.removeInternalItems(this.replacedItems(event));
- this.addItemsToCollection(this.items(event), this.collection, VALUES);
- }
-
- protected void itemsMoved(ListChangeEvent event) {
- // do nothing? moving items in a list has no net effect on a collection...
- }
-
- protected void listCleared(ListChangeEvent event) {
- // put in empty check so we don't fire events unnecessarily
- if ( ! this.collection.isEmpty()) {
- this.collection.clear();
- this.fireCollectionCleared(VALUES);
- }
- }
-
- /**
- * synchronize our internal collection with the wrapped list
- * and fire the appropriate events
- */
- protected void listChanged(ListChangeEvent event) {
- // put in empty check so we don't fire events unnecessarily
- if ( ! this.collection.isEmpty()) {
- @SuppressWarnings("unchecked")
- ArrayList<E> removedItems = (ArrayList<E>) this.collection.clone();
- this.collection.clear();
- this.fireItemsRemoved(VALUES, removedItems);
- }
-
- this.buildCollection();
- // put in empty check so we don't fire events unnecessarily
- if ( ! this.collection.isEmpty()) {
- this.fireItemsAdded(VALUES, this.collection);
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.listHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java
deleted file mode 100644
index f04821ad82..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListCurator.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This extension of AspectAdapter provides ListChange support
- * by adapting a subject's state change events to a minimum set
- * of list change events.
- */
-public abstract class ListCurator<S extends Model, E>
- extends AspectAdapter<S>
- implements ListValueModel<E>
-{
- /** How the list looked before the last state change */
- private final ArrayList<E> record;
-
- /** A listener that listens for the subject's state to change */
- private final StateChangeListener stateChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a Curator for the specified subject.
- */
- protected ListCurator(S subject) {
- this(new StaticPropertyValueModel<S>(subject));
- }
-
- /**
- * Construct a curator for the specified subject holder.
- * The subject holder cannot be null.
- */
- protected ListCurator(PropertyValueModel<? extends S> subjectHolder) {
- super(subjectHolder);
- this.record = new ArrayList<E>();
- this.stateChangeListener = this.buildStateChangeListener();
- }
-
-
- // ********** initialization **********
-
- /**
- * The subject's state has changed, do inventory and report to listeners.
- */
- protected StateChangeListener buildStateChangeListener() {
- return new StateChangeListener() {
- public void stateChanged(StateChangeEvent event) {
- ListCurator.this.submitInventoryReport();
- }
- @Override
- public String toString() {
- return "state change listener";
- }
- };
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E> listIterator() {
- return new ReadOnlyListIterator<E>(this.record);
- }
-
- /**
- * Return the item at the specified index of the subject's list aspect.
- */
- public E get(int index) {
- return this.record.get(index);
- }
-
- /**
- * Return the size of the subject's list aspect.
- */
- public int size() {
- return this.record.size();
- }
-
- /**
- * Return an array manifestation of the subject's list aspect.
- */
- public Object[] toArray() {
- return this.record.toArray();
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Object getValue() {
- return this.iterator();
- }
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return ListChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return LIST_VALUES;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyListChangeListeners(LIST_VALUES);
- }
-
- /**
- * The aspect has changed, notify listeners appropriately.
- */
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.fireListChanged(LIST_VALUES);
- }
-
- /**
- * The subject is not null - add our listener.
- */
- @Override
- protected void engageSubject_() {
- ((Model) this.subject).addStateChangeListener(this.stateChangeListener);
- // synch our list *after* we start listening to the subject,
- // since its value might change when a listener is added
- CollectionTools.addAll(this.record, this.iteratorForRecord());
- }
-
- /**
- * The subject is not null - remove our listener.
- */
- @Override
- protected void disengageSubject_() {
- ((Model) this.subject).removeStateChangeListener(this.stateChangeListener);
- // clear out the list when we are not listening to the subject
- this.record.clear();
- }
-
-
- // ********** ListCurator protocol **********
-
- /**
- * This is intended to be different from #ListValueModel.iterator().
- * It is intended to be used only when the subject changes or the
- * subject's "state" changes (as signified by a state change event).
- */
- protected abstract Iterator<E> iteratorForRecord();
-
-
- // ********** behavior **********
-
- void submitInventoryReport() {
- List<E> newRecord = CollectionTools.list(this.iteratorForRecord());
- int recordIndex = 0;
-
- // add items from the new record
- for (E newItem : newRecord) {
- this.inventoryNewItem(recordIndex, newItem);
- recordIndex++;
- }
-
- // clean out items that are no longer in the new record
- for (recordIndex = 0; recordIndex < this.record.size(); ) {
- E item = this.record.get(recordIndex);
-
- if (newRecord.contains(item)) {
- recordIndex++;
- } else {
- this.removeItemFromInventory(recordIndex, item);
- }
- }
- }
-
- private void inventoryNewItem(int recordIndex, E newItem) {
- List<E> rec = new ArrayList<E>(this.record);
-
- if ((recordIndex < rec.size()) && rec.get(recordIndex).equals(newItem)) {
- return;
- }
- if (rec.contains(newItem)) {
- this.removeItemFromInventory(recordIndex, rec.get(recordIndex));
- this.inventoryNewItem(recordIndex, newItem);
- } else {
- this.addItemToInventory(recordIndex, newItem);
- }
- }
-
- private void addItemToInventory(int index, E item) {
- this.addItemToList(index, item, this.record, LIST_VALUES);
- }
-
- private void removeItemFromInventory(int index, E item) {
- this.removeItemFromList(index, this.record, LIST_VALUES);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java
deleted file mode 100644
index 6c78b4fd62..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListPropertyValueModelAdapter.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a list value model, "lazily" listen to it, and convert
- * its change notifications into property value model change
- * notifications.
- *
- * Subclasses must override:
- * - #buildValue()
- * to return the current property value, as derived from the
- * current list value
- *
- * Subclasses might want to override:
- * - #itemsAdded(ListChangeEvent event)
- * - #itemsRemoved(ListChangeEvent event)
- * - #itemsReplaced(ListChangeEvent event)
- * - #itemsMoved(ListChangeEvent event)
- * - #listCleared(ListChangeEvent event)
- * - #listChanged(ListChangeEvent event)
- * to improve performance (by not recalculating the value, if possible)
- */
-public abstract class ListPropertyValueModelAdapter<T>
- extends AspectPropertyValueModelAdapter<T>
-{
- /** The wrapped list value model. */
- protected final ListValueModel<?> listHolder;
-
- /** A listener that allows us to synch with changes to the wrapped list holder. */
- protected final ListChangeListener listChangeListener;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * list value model.
- */
- protected ListPropertyValueModelAdapter(ListValueModel<?> listHolder) {
- super();
- this.listHolder = listHolder;
- this.listChangeListener = this.buildListChangeListener();
- }
-
- protected ListChangeListener buildListChangeListener() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.itemsRemoved(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.itemsReplaced(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.itemsMoved(event);
- }
- public void listCleared(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.listCleared(event);
- }
- public void listChanged(ListChangeEvent event) {
- ListPropertyValueModelAdapter.this.listChanged(event);
- }
- @Override
- public String toString() {
- return "list change listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the list holder.
- */
- @Override
- protected void engageModel_() {
- this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
- /**
- * Stop listening to the list holder.
- */
- @Override
- protected void disengageModel_() {
- this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.listHolder);
- }
-
-
- // ********** collection change support **********
-
- /**
- * Items were added to the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsAdded(ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were removed from the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsRemoved(ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were replaced in the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsReplaced(ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Items were moved in the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected void itemsMoved(ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The wrapped list holder was cleared;
- * propagate the change notification appropriately.
- */
- protected void listCleared(ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The value of the wrapped list holder has changed;
- * propagate the change notification appropriately.
- */
- protected void listChanged(ListChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java
deleted file mode 100644
index 06f5a072e5..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ListValueModelWrapper.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * another list value model, "lazily" listen to it, and propagate
- * its change notifications.
- */
-public abstract class ListValueModelWrapper<E>
- extends AbstractModel
-{
-
- /** The wrapped list value model. */
- protected final ListValueModel<? extends E> listHolder;
-
- /** A listener that allows us to synch with changes to the wrapped list holder. */
- protected final ListChangeListener listChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a list value model with the specified wrapped
- * list value model.
- */
- protected ListValueModelWrapper(ListValueModel<? extends E> listHolder) {
- super();
- if (listHolder == null) {
- throw new NullPointerException();
- }
- this.listHolder = listHolder;
- this.listChangeListener = this.buildListChangeListener();
- }
-
-
- // ********** initialization **********
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, ListChangeListener.class, ListValueModel.LIST_VALUES);
- }
-
- protected ListChangeListener buildListChangeListener() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ListValueModelWrapper.this.itemsAdded(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- ListValueModelWrapper.this.itemsRemoved(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- ListValueModelWrapper.this.itemsReplaced(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- ListValueModelWrapper.this.itemsMoved(event);
- }
- public void listCleared(ListChangeEvent event) {
- ListValueModelWrapper.this.listCleared(event);
- }
- public void listChanged(ListChangeEvent event) {
- ListValueModelWrapper.this.listChanged(event);
- }
- @Override
- public String toString() {
- return "list change listener";
- }
- };
- }
-
-
- // ********** extend change support **********
-
- /**
- * Extend to start listening to the nested model if necessary.
- */
- @Override
- public synchronized void addListChangeListener(ListChangeListener listener) {
- if (this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) {
- this.engageModel();
- }
- super.addListChangeListener(listener);
- }
-
- /**
- * Extend to start listening to the nested model if necessary.
- */
- @Override
- public synchronized void addListChangeListener(String listName, ListChangeListener listener) {
- if (listName == ListValueModel.LIST_VALUES && this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) {
- this.engageModel();
- }
- super.addListChangeListener(listName, listener);
- }
-
- /**
- * Extend to stop listening to the nested model if necessary.
- */
- @Override
- public synchronized void removeListChangeListener(ListChangeListener listener) {
- super.removeListChangeListener(listener);
- if (this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to stop listening to the nested model if necessary.
- */
- @Override
- public synchronized void removeListChangeListener(String listName, ListChangeListener listener) {
- super.removeListChangeListener(listName, listener);
- if (listName == ListValueModel.LIST_VALUES && this.hasNoListChangeListeners(ListValueModel.LIST_VALUES)) {
- this.disengageModel();
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the list holder.
- */
- protected void engageModel() {
- this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
- /**
- * Stop listening to the list holder.
- */
- protected void disengageModel() {
- this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.listHolder);
- }
-
- // minimize suppressed warnings
- @SuppressWarnings("unchecked")
- protected ListIterator<E> items(ListChangeEvent event) {
- return (ListIterator<E>) event.items();
- }
-
- // minimize suppressed warnings
- @SuppressWarnings("unchecked")
- protected ListIterator<E> replacedItems(ListChangeEvent event) {
- return (ListIterator<E>) event.replacedItems();
- }
-
-
- // ********** list change support **********
-
- /**
- * Items were added to the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected abstract void itemsAdded(ListChangeEvent event);
-
- /**
- * Items were removed from the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected abstract void itemsRemoved(ListChangeEvent event);
-
- /**
- * Items were replaced in the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected abstract void itemsReplaced(ListChangeEvent event);
-
- /**
- * Items were moved in the wrapped list holder;
- * propagate the change notification appropriately.
- */
- protected abstract void itemsMoved(ListChangeEvent event);
-
- /**
- * The wrapped list holder was cleared;
- * propagate the change notification appropriately.
- */
- protected abstract void listCleared(ListChangeEvent event);
-
- /**
- * The value of the wrapped list holder has changed;
- * propagate the change notification appropriately.
- */
- protected abstract void listChanged(ListChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java
deleted file mode 100644
index db6447c94b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullCollectionValueModel.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-
-/**
- * A read-only collection value model for when you
- * don't need to support a collection. In particular, this
- * is useful for the leaf nodes of a tree that never have
- * children.
- *
- * We don't use a singleton because we hold on to listeners.
- */
-public final class NullCollectionValueModel<E>
- extends AbstractModel
- implements CollectionValueModel<E>
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * Default constructor.
- */
- public NullCollectionValueModel() {
- super();
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- public int size() {
- return 0;
- }
-
- public Iterator<E> iterator() {
- return EmptyIterator.instance();
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return ClassTools.shortClassNameForObject(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java
deleted file mode 100644
index 7bdb3ab3a3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullListValueModel.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * An empty list value model for when you don't
- * need to support a list.
- *
- * We don't use a singleton because we hold on to listeners.
- */
-public final class NullListValueModel<E>
- extends AbstractModel
- implements ListValueModel<E>
-{
- private static final Object[] EMPTY_ARRAY = new Object[0];
- private static final long serialVersionUID = 1L;
-
- /**
- * Default constructor.
- */
- public NullListValueModel() {
- super();
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return EmptyIterator.instance();
- }
-
- public ListIterator<E> listIterator() {
- return EmptyListIterator.instance();
- }
-
- public int size() {
- return 0;
- }
-
- public E get(int index) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0");
- }
-
- public Object[] toArray() {
- return EMPTY_ARRAY;
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return ClassTools.shortClassNameForObject(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java
deleted file mode 100644
index 12c9b670e8..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullPropertyValueModel.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * A property value model for when you
- * don't need to support a value.
- *
- * We don't use a singleton because we hold on to listeners.
- */
-public class NullPropertyValueModel<T>
- extends AbstractModel
- implements PropertyValueModel<T>
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * Default constructor.
- */
- public NullPropertyValueModel() {
- super();
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- public T getValue() {
- return null;
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return ClassTools.shortClassNameForObject(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java
deleted file mode 100644
index b035c29811..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/NullTreeValueModel.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.TreeValueModel;
-
-/**
- * A tree value model for when you
- * don't need to support any nodes.
- *
- * We don't use a singleton because we hold on to listeners.
- */
-public class NullTreeValueModel<E>
- extends AbstractModel
- implements TreeValueModel<E>
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * Default constructor.
- */
- public NullTreeValueModel() {
- super();
- }
-
-
- // ********** TreeValueModel implementation **********
-
- public Iterator<E> nodes() {
- return EmptyIterator.instance();
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return ClassTools.shortClassNameForObject(this);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java
deleted file mode 100644
index eb2b4f8b43..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyAspectAdapter.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import java.util.Collection;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This AspectAdapter provides basic PropertyChange support.
- * This allows us to convert a set of one or more properties into
- * a single property, VALUE.
- *
- * The typical subclass will override the following methods:
- * #buildValue_()
- * at the very minimum, override this method to return the value of the
- * subject's property (or "virtual" property); it does not need to be
- * overridden if #buildValue() is overridden and its behavior changed
- * #setValue_(Object)
- * override this method if the client code needs to *set* the value of
- * the subject's property; oftentimes, though, the client code (e.g. UI)
- * will need only to *get* the value; it does not need to be
- * overridden if #setValue(Object) is overridden and its behavior changed
- * #buildValue()
- * override this method only if returning a null value when the subject is null
- * is unacceptable
- * #setValue(Object)
- * override this method only if something must be done when the subject
- * is null (e.g. throw an exception)
- */
-public abstract class PropertyAspectAdapter<S extends Model, T>
- extends AspectAdapter<S>
- implements WritablePropertyValueModel<T>
-{
- /**
- * Cache the current value of the aspect so we
- * can pass an "old value" when we fire a property change event.
- * We need this because the value may be calculated and may
- * not be in the property change event fired by the subject,
- * especially when dealing with multiple aspects.
- */
- protected T value;
-
- /** The name of the subject's properties that we use for the value. */
- protected final String[] propertyNames;
- protected static final String[] EMPTY_PROPERTY_NAMES = new String[0];
-
- /** A listener that listens to the appropriate properties of the subject. */
- protected final PropertyChangeListener propertyChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a PropertyAspectAdapter for the specified subject
- * and property.
- */
- protected PropertyAspectAdapter(String propertyName, S subject) {
- this(new String[] {propertyName}, subject);
- }
-
- /**
- * Construct a PropertyAspectAdapter for the specified subject
- * and properties.
- */
- protected PropertyAspectAdapter(String[] propertyNames, S subject) {
- this(new StaticPropertyValueModel<S>(subject), propertyNames);
- }
-
- /**
- * Construct a PropertyAspectAdapter for the specified subject holder
- * and properties.
- */
- protected PropertyAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... propertyNames) {
- super(subjectHolder);
- this.propertyNames = propertyNames;
- this.propertyChangeListener = this.buildPropertyChangeListener();
- // our value is null when we are not listening to the subject
- this.value = null;
- }
-
- /**
- * Construct a PropertyAspectAdapter for the specified subject holder
- * and properties.
- */
- protected PropertyAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> propertyNames) {
- this(subjectHolder, propertyNames.toArray(new String[propertyNames.size()]));
- }
-
- /**
- * Construct a PropertyAspectAdapter for an "unchanging" property in
- * the specified subject. This is useful for a property aspect that does not
- * change for a particular subject; but the subject will change, resulting in
- * a new property. (A TransformationPropertyValueModel could also be
- * used in this situation.)
- */
- protected PropertyAspectAdapter(PropertyValueModel<? extends S> subjectHolder) {
- this(subjectHolder, EMPTY_PROPERTY_NAMES);
- }
-
-
- // ********** initialization **********
-
- /**
- * The subject's property has changed, notify the listeners.
- */
- protected PropertyChangeListener buildPropertyChangeListener() {
- // transform the subject's property change events into VALUE property change events
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- PropertyAspectAdapter.this.propertyChanged();
- }
- @Override
- public String toString() {
- return "property change listener: " + Arrays.asList(PropertyAspectAdapter.this.propertyNames); //$NON-NLS-1$
- }
- };
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- /**
- * Return the value of the subject's property.
- */
- @Override
- public final T getValue() {
- return this.value;
- }
-
-
- // ********** WritablePropertyValueModel implementation **********
-
- /**
- * Set the value of the subject's property.
- */
- public void setValue(T value) {
- if (this.subject != null) {
- this.setValue_(value);
- }
- }
-
- /**
- * Set the value of the subject's property.
- * At this point we can be sure that the subject is not null.
- * @see #setValue(Object)
- */
- protected void setValue_(@SuppressWarnings("unused") T value) {
- throw new UnsupportedOperationException();
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return PropertyChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return VALUE;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyPropertyChangeListeners(VALUE);
- }
-
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.firePropertyChanged(VALUE, oldValue, newValue);
- }
-
- @Override
- protected void engageSubject() {
- super.engageSubject();
- // synch our value *after* we start listening to the subject,
- // since its value might change when a listener is added
- this.value = this.buildValue();
- }
-
- @Override
- protected void engageSubject_() {
- for (String propertyName : this.propertyNames) {
- ((Model) this.subject).addPropertyChangeListener(propertyName, this.propertyChangeListener);
- }
- }
-
- @Override
- protected void disengageSubject() {
- super.disengageSubject();
- // clear out our value when we are not listening to the subject
- this.value = null;
- }
-
- @Override
- protected void disengageSubject_() {
- for (String propertyName : this.propertyNames) {
- ((Model) this.subject).removePropertyChangeListener(propertyName, this.propertyChangeListener);
- }
- }
-
-
- // ********** AbstractModel implementation **********
-
- @Override
- public void toString(StringBuilder sb) {
- for (int i = 0; i < this.propertyNames.length; i++) {
- if (i != 0) {
- sb.append(", "); //$NON-NLS-1$
- }
- sb.append(this.propertyNames[i]);
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Return the aspect's value.
- * At this point the subject may be null.
- */
- protected T buildValue() {
- return (this.subject == null) ? null : this.buildValue_();
- }
-
- /**
- * Return the value of the subject's property.
- * At this point we can be sure that the subject is not null.
- * @see #buildValue()
- */
- protected T buildValue_() {
- throw new UnsupportedOperationException();
- }
-
- protected void propertyChanged() {
- T old = this.value;
- this.value = this.buildValue();
- this.fireAspectChange(old, this.value);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java
deleted file mode 100644
index 5b09ad161e..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyCollectionValueModelAdapter.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.internal.iterators.SingleElementIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * An adapter that allows us to make a PropertyValueModel behave like
- * a read-only, single-element CollectionValueModel, sorta.
- *
- * If the property's value is null, an empty iterator is returned
- * (i.e. you can't have a collection with a null element).
- */
-public class PropertyCollectionValueModelAdapter<E>
- extends AbstractModel
- implements CollectionValueModel<E>
-{
- /** The wrapped property value model. */
- protected final PropertyValueModel<? extends E> valueHolder;
-
- /** A listener that forwards any events fired by the value holder. */
- protected final PropertyChangeListener propertyChangeListener;
-
- /** Cache the value. */
- protected E value;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Wrap the specified ListValueModel.
- */
- public PropertyCollectionValueModelAdapter(PropertyValueModel<? extends E> valueHolder) {
- super();
- if (valueHolder == null) {
- throw new NullPointerException();
- }
- this.valueHolder = valueHolder;
- this.propertyChangeListener = this.buildPropertyChangeListener();
- // postpone building the value and listening to the underlying value
- // until we have listeners ourselves...
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, CollectionChangeListener.class, VALUES);
- }
-
- /**
- * The wrapped value has changed, forward an equivalent
- * collection change event to our listeners.
- */
- protected PropertyChangeListener buildPropertyChangeListener() {
- return new PropertyChangeListener() {
- @SuppressWarnings("unchecked")
- public void propertyChanged(PropertyChangeEvent event) {
- PropertyCollectionValueModelAdapter.this.valueChanged((E) event.getNewValue());
- }
- @Override
- public String toString() {
- return "property change listener";
- }
- };
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- public Iterator<E> iterator() {
- return (this.value == null) ?
- EmptyIterator.<E>instance()
- :
- new SingleElementIterator<E>(this.value);
- }
-
- public int size() {
- return (this.value == null) ? 0 : 1;
- }
-
-
- // ********** extend change support **********
-
- /**
- * Override to start listening to the value holder if necessary.
- */
- @Override
- public void addCollectionChangeListener(CollectionChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addCollectionChangeListener(listener);
- }
-
- /**
- * Override to start listening to the value holder if necessary.
- */
- @Override
- public void addCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- if (collectionName == VALUES && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addCollectionChangeListener(collectionName, listener);
- }
-
- /**
- * Override to stop listening to the value holder if appropriate.
- */
- @Override
- public void removeCollectionChangeListener(CollectionChangeListener listener) {
- super.removeCollectionChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Override to stop listening to the value holder if appropriate.
- */
- @Override
- public void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener) {
- super.removeCollectionChangeListener(collectionName, listener);
- if (collectionName == VALUES && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** queries **********
-
- protected boolean hasListeners() {
- return this.hasAnyCollectionChangeListeners(VALUES);
- }
-
- protected boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
-
- // ********** behavior **********
-
- protected void engageModel() {
- this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.propertyChangeListener);
- // synch our value *after* we start listening to the value holder,
- // since its value might change when a listener is added
- this.value = this.valueHolder.getValue();
- }
-
- protected void disengageModel() {
- this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.propertyChangeListener);
- // clear out the value when we are not listening to the value holder
- this.value = null;
- }
-
- /**
- * synchronize our internal value with the wrapped value
- * and fire the appropriate events
- */
- protected void valueChanged(E newValue) {
- // put in "empty" check so we don't fire events unnecessarily
- if (this.value != null) {
- E oldValue = this.value;
- this.value = null;
- this.fireItemRemoved(VALUES, oldValue);
- }
- this.value = newValue;
- // put in "empty" check so we don't fire events unnecessarily
- if (this.value != null) {
- this.fireItemAdded(VALUES, this.value);
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.valueHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyListValueModelAdapter.java
deleted file mode 100644
index 96afe29e1f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyListValueModelAdapter.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator;
-import org.eclipse.jpt.utility.internal.iterators.SingleElementListIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * An adapter that allows us to make a PropertyValueModel behave like
- * a read-only, single-element ListValueModel, sorta.
- *
- * If the property's value is null, an empty iterator is returned
- * (i.e. you can't have a list with a null element).
- */
-public class PropertyListValueModelAdapter<E>
- extends AbstractModel
- implements ListValueModel<E>
-{
-
- /** The wrapped property value model. */
- protected final PropertyValueModel<? extends E> valueHolder;
-
- /** A listener that forwards any events fired by the value holder. */
- protected final PropertyChangeListener propertyChangeListener;
-
- /** Cache the value. */
- protected E value;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Wrap the specified property value model.
- */
- public PropertyListValueModelAdapter(PropertyValueModel<? extends E> valueHolder) {
- super();
- if (valueHolder == null) {
- throw new NullPointerException();
- }
- this.valueHolder = valueHolder;
- this.propertyChangeListener = this.buildPropertyChangeListener();
- // postpone building the value and listening to the underlying value
- // until we have listeners ourselves...
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, ListChangeListener.class, LIST_VALUES);
- }
-
- /**
- * The wrapped value has changed, forward an equivalent
- * list change event to our listeners.
- */
- protected PropertyChangeListener buildPropertyChangeListener() {
- return new PropertyChangeListener() {
- @SuppressWarnings("unchecked")
- public void propertyChanged(PropertyChangeEvent event) {
- PropertyListValueModelAdapter.this.valueChanged((E) event.getNewValue());
- }
- @Override
- public String toString() {
- return "property change listener";
- }
- };
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E> listIterator() {
- return (this.value == null) ?
- EmptyListIterator.<E>instance()
- :
- new SingleElementListIterator<E>(this.value);
- }
-
- public int size() {
- return (this.value == null) ? 0 : 1;
- }
-
- public E get(int index) {
- if (this.value == null) {
- throw this.ioobe(index, 0);
- }
- if (index > 0) {
- throw this.ioobe(index, 1);
- }
- return this.value;
- }
-
- protected static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
- public Object[] toArray() {
- return (this.value == null) ? EMPTY_OBJECT_ARRAY : new Object[] {this.value};
- }
-
-
- // ********** extend change support **********
-
- /**
- * Override to start listening to the value holder if necessary.
- */
- @Override
- public void addListChangeListener(ListChangeListener listener) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addListChangeListener(listener);
- }
-
- /**
- * Override to start listening to the value holder if necessary.
- */
- @Override
- public void addListChangeListener(String listName, ListChangeListener listener) {
- if (listName == LIST_VALUES && this.hasNoListeners()) {
- this.engageModel();
- }
- super.addListChangeListener(listName, listener);
- }
-
- /**
- * Override to stop listening to the value holder if appropriate.
- */
- @Override
- public void removeListChangeListener(ListChangeListener listener) {
- super.removeListChangeListener(listener);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Override to stop listening to the value holder if appropriate.
- */
- @Override
- public void removeListChangeListener(String listName, ListChangeListener listener) {
- super.removeListChangeListener(listName, listener);
- if (listName == LIST_VALUES && this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** queries **********
-
- protected boolean hasListeners() {
- return this.hasAnyListChangeListeners(LIST_VALUES);
- }
-
- protected boolean hasNoListeners() {
- return ! this.hasListeners();
- }
-
-
- // ********** behavior **********
-
- protected IndexOutOfBoundsException ioobe(int index, int size) {
- return new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
- }
-
- protected void engageModel() {
- this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.propertyChangeListener);
- // synch our value *after* we start listening to the value holder,
- // since its value might change when a listener is added
- this.value = this.valueHolder.getValue();
- }
-
- protected void disengageModel() {
- this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.propertyChangeListener);
- // clear out the value when we are not listening to the value holder
- this.value = null;
- }
-
- /**
- * synchronize our internal value with the wrapped value
- * and fire the appropriate events
- */
- protected void valueChanged(E newValue) {
- E oldValue = this.value;
- this.value = newValue;
- if (oldValue == null) {
- this.fireItemAdded(LIST_VALUES, 0, newValue);
- } else {
- if (newValue == null) {
- this.fireItemRemoved(LIST_VALUES, 0, oldValue);
- } else {
- this.fireItemReplaced(LIST_VALUES, 0, newValue, oldValue);
- }
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.valueHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java
deleted file mode 100644
index c5195af061..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/PropertyValueModelWrapper.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * another property value model, "lazily" listen to it, and propagate
- * its change notifications.
- */
-public abstract class PropertyValueModelWrapper<T>
- extends AbstractModel
-{
-
- /** The wrapped property value model. */
- protected final PropertyValueModel<? extends T> valueHolder;
-
- /** A listener that allows us to synch with changes to the wrapped value holder. */
- protected final PropertyChangeListener valueChangeListener;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * property value model. The value holder is required.
- */
- protected PropertyValueModelWrapper(PropertyValueModel<? extends T> valueHolder) {
- super();
- if (valueHolder == null) {
- throw new NullPointerException();
- }
- this.valueHolder = valueHolder;
- this.valueChangeListener = this.buildValueChangeListener();
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, PropertyChangeListener.class, PropertyValueModel.VALUE);
- }
-
- protected PropertyChangeListener buildValueChangeListener() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- PropertyValueModelWrapper.this.valueChanged(event);
- }
- @Override
- public String toString() {
- return "value change listener"; //$NON-NLS-1$
- }
- };
- }
-
-
- // ********** extend change support **********
-
- /**
- * Extend to start listening to the nested model if necessary.
- */
- @Override
- public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
- if (this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) {
- this.engageValueHolder();
- }
- super.addPropertyChangeListener(listener);
- }
-
- /**
- * Extend to start listening to the nested model if necessary.
- */
- @Override
- public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- if (propertyName == PropertyValueModel.VALUE && this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) {
- this.engageValueHolder();
- }
- super.addPropertyChangeListener(propertyName, listener);
- }
-
- /**
- * Extend to stop listening to the nested model if necessary.
- */
- @Override
- public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
- super.removePropertyChangeListener(listener);
- if (this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) {
- this.disengageValueHolder();
- }
- }
-
- /**
- * Extend to stop listening to the nested model if necessary.
- */
- @Override
- public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
- super.removePropertyChangeListener(propertyName, listener);
- if (propertyName == PropertyValueModel.VALUE && this.hasNoPropertyChangeListeners(PropertyValueModel.VALUE)) {
- this.disengageValueHolder();
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Begin listening to the value holder.
- */
- protected void engageValueHolder() {
- this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
- }
-
- /**
- * Stop listening to the value holder.
- */
- protected void disengageValueHolder() {
- this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.valueHolder);
- }
-
-
- // ********** property change support **********
-
- /**
- * The value of the wrapped value holder has changed;
- * propagate the change notification appropriately.
- */
- protected abstract void valueChanged(PropertyChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java
deleted file mode 100644
index e61c51136d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleCollectionValueModel.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.HashBag;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-
-/**
- * Implementation of CollectionValueModel and Collection that simply holds a
- * collection and notifies listeners of any changes.
- */
-public class SimpleCollectionValueModel<E>
- extends AbstractModel
- implements CollectionValueModel<E>, Collection<E>
-{
- /** The collection. */
- protected Collection<E> collection;
-
-
- // ********** constructors **********
-
- /**
- * Construct a CollectionValueModel for the specified collection.
- */
- public SimpleCollectionValueModel(Collection<E> collection) {
- super();
- if (collection == null) {
- throw new NullPointerException();
- }
- this.collection = collection;
- }
-
- /**
- * Construct a CollectionValueModel with an empty initial collection.
- */
- public SimpleCollectionValueModel() {
- this(new HashBag<E>());
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, CollectionChangeListener.class, VALUES);
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- public Iterator<E> iterator() {
- return new LocalIterator<E>(this.collection.iterator());
- }
-
- public int size() {
- return this.collection.size();
- }
-
-
- // ********** Collection implementation **********
-
- public boolean isEmpty() {
- return this.collection.isEmpty();
- }
-
- public boolean contains(Object o) {
- return this.collection.contains(o);
- }
-
- public Object[] toArray() {
- return this.collection.toArray();
- }
-
- public <T extends Object> T[] toArray(T[] a) {
- return this.collection.toArray(a);
- }
-
- public boolean add(E o) {
- return this.addItemToCollection(o, this.collection, VALUES);
- }
-
- public boolean remove(Object o) {
- return this.removeItemFromCollection(o, this.collection, VALUES);
- }
-
- public boolean containsAll(Collection<?> c) {
- return this.collection.containsAll(c);
- }
-
- public boolean addAll(Collection<? extends E> c) {
- return this.addItemsToCollection(c, this.collection, VALUES);
- }
-
- public boolean removeAll(Collection<?> c) {
- return this.removeItemsFromCollection(c, this.collection, VALUES);
- }
-
- public boolean retainAll(Collection<?> c) {
- return this.retainItemsInCollection(c, this.collection, VALUES);
- }
-
- public void clear() {
- this.clearCollection(this.collection, VALUES);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if ((o instanceof Collection) && (o instanceof CollectionValueModel)) {
- Collection<E> c1 = CollectionTools.collection(this.collection);
- @SuppressWarnings("unchecked")
- Collection<E> c2 = CollectionTools.collection(((Collection<E>) o).iterator());
- return c1.equals(c2);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return CollectionTools.collection(this.collection).hashCode();
- }
-
-
- // ********** additional behavior **********
-
- /**
- * Allow the collection to be replaced.
- */
- public void setCollection(Collection<E> collection) {
- if (collection == null) {
- throw new NullPointerException();
- }
- this.collection = collection;
- this.fireCollectionChanged(VALUES);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.collection);
- }
-
-
- // ********** iterator **********
-
- private class LocalIterator<T> implements Iterator<T> {
- private final Iterator<T> iterator;
- private T next;
-
- LocalIterator(Iterator<T> iterator) {
- super();
- this.iterator = iterator;
- }
-
- public boolean hasNext() {
- return this.iterator.hasNext();
- }
-
- public T next() {
- return this.next = this.iterator.next();
- }
-
- @SuppressWarnings("synthetic-access")
- public void remove() {
- this.iterator.remove();
- SimpleCollectionValueModel.this.fireItemRemoved(VALUES, this.next);
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java
deleted file mode 100644
index e6aca61c50..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimpleListValueModel.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Implementation of ListValueModel and List that simply holds a
- * collection and notifies listeners of any changes.
- */
-public class SimpleListValueModel<E>
- extends AbstractModel
- implements ListValueModel<E>, List<E>
-{
- /** The list. */
- protected List<E> list;
-
-
- // ********** constructors **********
-
- /**
- * Construct a ListValueModel for the specified list.
- */
- public SimpleListValueModel(List<E> list) {
- super();
- if (list == null) {
- throw new NullPointerException();
- }
- this.list = list;
- }
-
- /**
- * Construct a ListValueModel with an empty initial list.
- */
- public SimpleListValueModel() {
- this(new ArrayList<E>());
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, ListChangeListener.class, LIST_VALUES);
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return new LocalIterator<E>(this.list.iterator());
- }
-
- public ListIterator<E> listIterator() {
- return new LocalListIterator<E>(this.list.listIterator());
- }
-
- public int size() {
- return this.list.size();
- }
-
- public E get(int index) {
- return this.list.get(index);
- }
-
-
- // ********** List implementation **********
-
- public boolean isEmpty() {
- return this.list.isEmpty();
- }
-
- public boolean contains(Object o) {
- return this.list.contains(o);
- }
-
- public Object[] toArray() {
- return this.list.toArray();
- }
-
- public <T extends Object> T[] toArray(T[] a) {
- return this.list.toArray(a);
- }
-
- public boolean add(E o) {
- return this.addItemToList(o, this.list, LIST_VALUES);
- }
-
- public boolean remove(Object o) {
- return this.removeItemFromList(o, this.list, LIST_VALUES);
- }
-
- public boolean containsAll(Collection<?> c) {
- return this.list.containsAll(c);
- }
-
- public boolean addAll(Collection<? extends E> c) {
- return this.addItemsToList(c, this.list, LIST_VALUES);
- }
-
- public boolean addAll(int index, Collection<? extends E> c) {
- return this.addItemsToList(index, c, this.list, LIST_VALUES);
- }
-
- public boolean removeAll(Collection<?> c) {
- return this.removeItemsFromList(c, this.list, LIST_VALUES);
- }
-
- public boolean retainAll(Collection<?> c) {
- return this.retainItemsInList(c, this.list, LIST_VALUES);
- }
-
- public void clear() {
- this.clearList(this.list, LIST_VALUES);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if ((o instanceof List) && (o instanceof ListValueModel)) {
- List<E> l1 = CollectionTools.list(this.list);
- @SuppressWarnings("unchecked")
- List<E> l2 = CollectionTools.list(((List<E>) o).iterator());
- return l1.equals(l2);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return this.list.hashCode();
- }
-
- public E set(int index, E element) {
- return this.setItemInList(index, element, this.list, LIST_VALUES);
- }
-
- public void add(int index, E element) {
- this.addItemToList(index, element, this.list, LIST_VALUES);
- }
-
- public E remove(int index) {
- return this.removeItemFromList(index, this.list, LIST_VALUES);
- }
-
- public int indexOf(Object o) {
- return this.list.indexOf(o);
- }
-
- public int lastIndexOf(Object o) {
- return this.list.lastIndexOf(o);
- }
-
- public ListIterator<E> listIterator(int index) {
- return new LocalListIterator<E>(this.list.listIterator(index));
- }
-
- public List<E> subList(int fromIndex, int toIndex) {
- // TODO hmmm ~bjv
- throw new UnsupportedOperationException();
- }
-
-
- // ********** additional behavior **********
-
- /**
- * Allow the list to be replaced.
- */
- public void setList(List<E> list) {
- if (list == null) {
- throw new NullPointerException();
- }
- this.list = list;
- this.fireListChanged(LIST_VALUES);
- }
-
- /**
- * Move a single element.
- */
- public void move(int targetIndex, int sourceIndex) {
- this.moveItemInList(targetIndex, sourceIndex, this.list, LIST_VALUES);
- }
-
- /**
- * Move a sub-list of elements.
- */
- public void move(int targetIndex, int sourceIndex, int length) {
- this.moveItemsInList(targetIndex, sourceIndex, length, this.list, LIST_VALUES);
- }
-
- /**
- * Remove a range of elements.
- */
- public void remove(int index, int length) {
- this.removeItemsFromList(index, length, this.list, LIST_VALUES);
- }
-
- /**
- * Set a range of elements.
- */
- public void set(int index, List<E> elements) {
- this.setItemsInList(index, elements, this.list, LIST_VALUES);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.list);
- }
-
-
- // ********** iterators **********
-
- private class LocalIterator<T> implements Iterator<T> {
- private final Iterator<T> iterator;
- private int index = -1;
- private T next;
-
- LocalIterator(Iterator<T> iterator) {
- super();
- this.iterator = iterator;
- }
-
- public boolean hasNext() {
- return this.iterator.hasNext();
- }
-
- public T next() {
- this.next = this.iterator.next();
- this.index++;
- return this.next;
- }
-
- @SuppressWarnings("synthetic-access")
- public void remove() {
- this.iterator.remove();
- SimpleListValueModel.this.fireItemRemoved(LIST_VALUES, this.index, this.next);
- }
-
- }
-
- private class LocalListIterator<T> implements ListIterator<T> {
- private final ListIterator<T> iterator;
- private int last = -1;
- private int next = 0;
- private T current;
-
- LocalListIterator(ListIterator<T> iterator) {
- super();
- this.iterator = iterator;
- }
-
- public boolean hasNext() {
- return this.iterator.hasNext();
- }
-
- public T next() {
- this.current = this.iterator.next();
- this.last = this.next++;
- return this.current;
- }
-
- public int nextIndex() {
- return this.iterator.nextIndex();
- }
-
- public boolean hasPrevious() {
- return this.iterator.hasPrevious();
- }
-
- public T previous() {
- this.current = this.iterator.previous();
- this.last = --this.next;
- return this.current;
- }
-
- public int previousIndex() {
- return this.iterator.previousIndex();
- }
-
- @SuppressWarnings("synthetic-access")
- public void set(T o) {
- this.iterator.set(o);
- SimpleListValueModel.this.fireItemReplaced(LIST_VALUES, this.last, o, this.current);
- }
-
- @SuppressWarnings("synthetic-access")
- public void add(T o) {
- this.iterator.add(o);
- SimpleListValueModel.this.fireItemAdded(LIST_VALUES, this.next, o);
- }
-
- @SuppressWarnings("synthetic-access")
- public void remove() {
- this.iterator.remove();
- SimpleListValueModel.this.fireItemRemoved(LIST_VALUES, this.last, this.current);
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java
deleted file mode 100644
index e7248e65c5..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SimplePropertyValueModel.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.internal.model.SingleAspectChangeSupport;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Implementation of WritablePropertyValueModel that simply holds on to an
- * object and uses it as the value.
- */
-public class SimplePropertyValueModel<T>
- extends AbstractModel
- implements WritablePropertyValueModel<T>
-{
- /** The value. */
- protected T value;
-
-
- /**
- * Construct a PropertyValueModel for the specified value.
- */
- public SimplePropertyValueModel(T value) {
- super();
- this.value = value;
- }
-
- /**
- * Construct a PropertyValueModel with a starting value of null.
- */
- public SimplePropertyValueModel() {
- this(null);
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new SingleAspectChangeSupport(this, PropertyChangeListener.class, VALUE);
- }
-
-
- public T getValue() {
- return this.value;
- }
-
- public void setValue(T value) {
- T old = this.value;
- this.value = value;
- this.firePropertyChanged(VALUE, old, value);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.value);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java
deleted file mode 100644
index 2194ba4cb2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/SortedListValueModelAdapter.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.Range;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * An adapter that allows us to make a <code>CollectionValueModel</code>
- * (or <code>ListValueModel</code>) behave like a <code>ListValueModel</code>
- * that keeps its contents sorted and notifies listeners appropriately.
- * <p>
- * The comparator can be changed at any time; allowing the same
- * adapter to be used with different sort criteria (e.g. when the user
- * wants to sort a list of files first by name, then by date, then by size).
- * <p>
- * NB: Since we only listen to the wrapped collection when we have
- * listeners ourselves and we can only stay in synch with the wrapped
- * collection while we are listening to it, results to various methods
- * (e.g. <code>#size()</code>, <code>#getItem(int)</code>) will be
- * unpredictable whenever
- * we do not have any listeners. This should not be too painful since,
- * most likely, client objects will also be listeners.
- */
-public class SortedListValueModelAdapter<E>
- extends CollectionListValueModelAdapter<E>
-{
- /**
- * A comparator used for sorting the elements;
- * if it is null, we use "natural ordering".
- */
- protected Comparator<E> comparator;
-
-
- // ********** constructors **********
-
- /**
- * Wrap the specified collection value model and sort its contents
- * using the specified comparator.
- */
- public SortedListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder, Comparator<E> comparator) {
- super(collectionHolder);
- this.comparator = comparator;
- }
-
- /**
- * Wrap the specified collection value model and sort its contents
- * based on the elements' "natural ordering".
- */
- public SortedListValueModelAdapter(CollectionValueModel<? extends E> collectionHolder) {
- this(collectionHolder, null);
- }
-
- /**
- * Wrap the specified list value model and sort its contents
- * using the specified comparator.
- */
- public SortedListValueModelAdapter(ListValueModel<? extends E> listHolder, Comparator<E> comparator) {
- this(new ListCollectionValueModelAdapter<E>(listHolder), comparator);
- }
-
- /**
- * Wrap the specified list value model and sort its contents
- * based on the elements' "natural ordering".
- */
- public SortedListValueModelAdapter(ListValueModel<? extends E> listHolder) {
- this(listHolder, null);
- }
-
-
- // ********** accessors **********
-
- public void setComparator(Comparator<E> comparator) {
- this.comparator = comparator;
- this.sortList();
- }
-
-
- // ********** behavior **********
-
- /**
- * Sort the internal list before
- * sending out change notification.
- */
- @Override
- protected void postBuildList() {
- super.postBuildList();
- Collections.sort(this.list, this.comparator);
- }
-
- /**
- * the list will need to be sorted after the item is added
- */
- @Override
- protected void itemsAdded(CollectionChangeEvent event) {
- // first add the items and notify our listeners...
- super.itemsAdded(event);
- // ...then sort the list
- this.sortList();
- }
-
- /**
- * sort the list and notify our listeners, if necessary;
- */
- protected void sortList() {
- // save the unsorted state of the sorted list so we can minimize the number of "replaced" items
- @SuppressWarnings("unchecked")
- ArrayList<E> unsortedList = (ArrayList<E>) this.list.clone();
- Collections.sort(this.list, this.comparator);
- Range diffRange = CollectionTools.identityDiffRange(unsortedList, this.list);
- if (diffRange.size > 0) {
- List<E> unsortedItems = unsortedList.subList(diffRange.start, diffRange.end + 1);
- List<E> sortedItems = this.list.subList(diffRange.start, diffRange.end + 1);
- this.fireItemsReplaced(LIST_VALUES, diffRange.start, sortedItems, unsortedItems);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java
deleted file mode 100644
index db6c0c916f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StatePropertyValueModelAdapter.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a model, "lazily" listen to it, and convert
- * its state change notifications into property value model change
- * notifications.
- *
- * Subclasses must override:
- * - #buildValue()
- * to return the current property value, as derived from the
- * current model
- *
- * Subclasses might want to override:
- * - #stateChanged(StateChangeEvent event)
- * to improve performance (by not recalculating the value, if possible)
- */
-public abstract class StatePropertyValueModelAdapter<T>
- extends AspectPropertyValueModelAdapter<T>
-{
- /** The wrapped model. */
- protected final Model model;
-
- /** A listener that allows us to synch with changes to the wrapped model. */
- protected final StateChangeListener stateChangeListener;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped model.
- */
- protected StatePropertyValueModelAdapter(Model model) {
- super();
- this.model = model;
- this.stateChangeListener = this.buildStateChangeListener();
- }
-
- protected StateChangeListener buildStateChangeListener() {
- return new StateChangeListener() {
- public void stateChanged(StateChangeEvent event) {
- StatePropertyValueModelAdapter.this.stateChanged(event);
- }
- @Override
- public String toString() {
- return "state change listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the model.
- */
- @Override
- protected void engageModel_() {
- this.model.addStateChangeListener(this.stateChangeListener);
- }
-
- /**
- * Stop listening to the model.
- */
- @Override
- protected void disengageModel_() {
- this.model.removeStateChangeListener(this.stateChangeListener);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.model);
- }
-
-
- // ********** state change support **********
-
- /**
- * The model's state changed;
- * propagate the change notification appropriately.
- */
- protected void stateChanged(StateChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java
deleted file mode 100644
index 4cbcba4527..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticCollectionValueModel.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-
-/**
- * Implementation of CollectionValueModel that can be used for
- * returning an iterator on a static collection, but still allows listeners to be added.
- * Listeners will NEVER be notified of any changes, because there should be none.
- */
-public class StaticCollectionValueModel<E>
- extends AbstractModel
- implements CollectionValueModel<E>
-{
- /** The collection. */
- protected final Collection<? extends E> collection;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct a static CollectionValueModel for the specified collection.
- */
- public StaticCollectionValueModel(Collection<? extends E> collection) {
- super();
- if (collection == null) {
- throw new NullPointerException();
- }
- this.collection = collection;
- }
-
- // ********** CollectionValueModel implementation **********
-
- public int size() {
- return this.collection.size();
- }
-
- public Iterator<E> iterator() {
- return new ReadOnlyIterator<E>(this.collection.iterator());
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.collection);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java
deleted file mode 100644
index 3ddae7920d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticListValueModel.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * Implementation of ListValueModel that can be used for
- * returning a list iterator on a static list, but still allows listeners to be added.
- * Listeners will NEVER be notified of any changes, because there should be none.
- */
-public class StaticListValueModel<E>
- extends AbstractModel
- implements ListValueModel<E>
-{
- /** The value. */
- protected final List<? extends E> list;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct a static ListValueModel for the specified list.
- */
- public StaticListValueModel(List<? extends E> list) {
- super();
- if (list == null) {
- throw new NullPointerException();
- }
- this.list = list;
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E> iterator() {
- return new ReadOnlyIterator<E>(this.list.iterator());
- }
-
- public ListIterator<E> listIterator() {
- return new ReadOnlyListIterator<E>(this.list.listIterator());
- }
-
- public int size() {
- return this.list.size();
- }
-
- public E get(int index) {
- return this.list.get(index);
- }
-
- public Object[] toArray() {
- return this.list.toArray();
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.list);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java
deleted file mode 100644
index e5eccf3ae2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticPropertyValueModel.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * Implementation of PropertyValueModel that can be used for
- * returning a static value, but still allows listeners to be added.
- * Listeners will NEVER be notified of any changes, because there should be none.
- */
-public class StaticPropertyValueModel<T>
- extends AbstractModel
- implements PropertyValueModel<T>
-{
- /** The value. */
- protected final T value;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct a static PropertyValueModel for the specified value.
- */
- public StaticPropertyValueModel(T value) {
- super();
- this.value = value;
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- public T getValue() {
- return this.value;
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.value);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java
deleted file mode 100644
index 6c435a3238..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/StaticTreeValueModel.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.model.value.TreeValueModel;
-
-/**
- * Implementation of TreeValueModel that can be used for
- * returning an iterator on a static tree, but still allows listeners to be added.
- * Listeners will NEVER be notified of any changes, because there should be none.
- */
-public class StaticTreeValueModel<E>
- extends AbstractModel
- implements TreeValueModel<E>
-{
- /** The tree's nodes. */
- protected final Iterable<? extends E> nodes;
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct a read-only TreeValueModel for the specified nodes.
- */
- public StaticTreeValueModel(Iterable<? extends E> nodes) {
- super();
- if (nodes == null) {
- throw new NullPointerException();
- }
- this.nodes = nodes;
- }
-
- // ********** TreeValueModel implementation **********
-
- public Iterator<E> nodes() {
- return new ReadOnlyIterator<E>(this.nodes.iterator());
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, CollectionTools.collection(this.nodes()));
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java
deleted file mode 100644
index f1a7c1f877..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationListValueModelAdapter.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.Transformer;
-import org.eclipse.jpt.utility.internal.iterators.ReadOnlyListIterator;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * An adapter that allows us to transform a ListValueModel
- * (or CollectionValueModel) into a read-only ListValueModel
- * whose items are tranformations of the items in the wrapped
- * ListValueModel. It will keep its contents in synch with
- * the contents of the wrapped ListValueModel and notifies its
- * listeners of any changes.
- * <p>
- * The transformer can be changed at any time; allowing the same
- * adapter to be used with different transformations.
- * <p>
- * NB: Since we only listen to the wrapped list when we have
- * listeners ourselves and we can only stay in synch with the wrapped
- * list while we are listening to it, results to various methods
- * (e.g. #size(), #getItem(int)) will be unpredictable whenever
- * we do not have any listeners. This should not be too painful since,
- * most likely, client objects will also be listeners.
- */
-public class TransformationListValueModelAdapter<E1, E2>
- extends ListValueModelWrapper<E1>
- implements ListValueModel<E2>
-{
-
- /** This transforms the items, unless the subclass overrides #transformItem(Object). */
- protected Transformer<E1, E2> transformer;
-
- /** The list of transformed items. */
- protected final List<E2> transformedList;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the list holder is required.
- */
- public TransformationListValueModelAdapter(ListValueModel<? extends E1> listHolder, Transformer<E1, E2> transformer) {
- super(listHolder);
- this.transformer = transformer;
- this.transformedList = new ArrayList<E2>();
- }
-
- /**
- * Constructor - the list holder is required.
- */
- public TransformationListValueModelAdapter(ListValueModel<? extends E1> listHolder) {
- this(listHolder, Transformer.Null.<E1, E2>instance());
- }
-
- /**
- * Constructor - the collection holder is required.
- */
- public TransformationListValueModelAdapter(CollectionValueModel<? extends E1> collectionHolder, Transformer<E1, E2> transformer) {
- this(new CollectionListValueModelAdapter<E1>(collectionHolder), transformer);
- }
-
- /**
- * Constructor - the collection holder is required.
- */
- public TransformationListValueModelAdapter(CollectionValueModel<? extends E1> collectionHolder) {
- this(new CollectionListValueModelAdapter<E1>(collectionHolder));
- }
-
-
- // ********** ListValueModel implementation **********
-
- public Iterator<E2> iterator() {
- return this.listIterator();
- }
-
- public ListIterator<E2> listIterator() {
- return new ReadOnlyListIterator<E2>(this.transformedList);
- }
-
- public E2 get(int index) {
- return this.transformedList.get(index);
- }
-
- public int size() {
- return this.transformedList.size();
- }
-
- public Object[] toArray() {
- return this.transformedList.toArray();
- }
-
- // ********** behavior **********
-
- @Override
- protected void engageModel() {
- super.engageModel();
- // synch the transformed list *after* we start listening to the list holder,
- // since its value might change when a listener is added
- this.transformedList.addAll(this.transformItems(this.listHolder));
- }
-
- @Override
- protected void disengageModel() {
- super.disengageModel();
- // clear out the list when we are not listening to the collection holder
- this.transformedList.clear();
- }
-
- /**
- * Transform the items associated with the specified event.
- */
- protected List<E2> transformItems(ListChangeEvent event) {
- return this.transformItems(this.items(event), event.itemsSize());
- }
-
- /**
- * Transform the items in the specified list value model.
- */
- protected List<E2> transformItems(ListValueModel<? extends E1> lvm) {
- return this.transformItems(lvm.listIterator(), lvm.size());
- }
-
- /**
- * Transform the replaced items associated with the specified event.
- */
- protected List<E2> transformReplacedItems(ListChangeEvent event) {
- return this.transformItems(this.replacedItems(event), event.itemsSize());
- }
-
- /**
- * Transform the specified items.
- */
- protected List<E2> transformItems(ListIterator<? extends E1> items, int size) {
- List<E2> result = new ArrayList<E2>(size);
- while (items.hasNext()) {
- result.add(this.transformItem(items.next()));
- }
- return result;
- }
-
- /**
- * Transform the specified item.
- */
- protected E2 transformItem(E1 item) {
- return this.transformer.transform(item);
- }
-
- /**
- * Change the transformer and rebuild the collection.
- */
- public void setTransformer(Transformer<E1, E2> transformer) {
- this.transformer = transformer;
- this.rebuildTransformedList();
- }
-
- /**
- * Synchronize our cache with the wrapped collection.
- */
- protected void rebuildTransformedList() {
- this.transformedList.clear();
- this.transformedList.addAll(this.transformItems(this.listHolder));
- this.fireListChanged(LIST_VALUES);
- }
-
-
- // ********** list change support **********
-
- /**
- * Items were added to the wrapped list holder.
- * Transform them, add them to our transformation list,
- * and notify our listeners.
- */
- @Override
- protected void itemsAdded(ListChangeEvent event) {
- this.addItemsToList(event.getIndex(), this.transformItems(event), this.transformedList, LIST_VALUES);
- }
-
- /**
- * Items were removed from the wrapped list holder.
- * Remove the corresponding items from our transformation list
- * and notify our listeners.
- */
- @Override
- protected void itemsRemoved(ListChangeEvent event) {
- this.removeItemsFromList(event.getIndex(), event.itemsSize(), this.transformedList, LIST_VALUES);
- }
-
- /**
- * Items were replaced in the wrapped list holder.
- * Replace the corresponding items in our transformation list
- * and notify our listeners.
- */
- @Override
- protected void itemsReplaced(ListChangeEvent event) {
- this.setItemsInList(event.getIndex(), this.transformItems(event), this.transformedList, LIST_VALUES);
- }
-
- /**
- * Items were moved in the wrapped list holder.
- * Move the corresponding items in our transformation list
- * and notify our listeners.
- */
- @Override
- protected void itemsMoved(ListChangeEvent event) {
- this.moveItemsInList(event.getTargetIndex(), event.getSourceIndex(), event.getMoveLength(), this.transformedList, LIST_VALUES);
- }
-
- /**
- * The wrapped list holder was cleared.
- * Clear our transformation list and notify our listeners.
- */
- @Override
- protected void listCleared(ListChangeEvent event) {
- this.clearList(this.transformedList, LIST_VALUES);
- }
-
- /**
- * The wrapped list holder has changed in some dramatic fashion.
- * Rebuild our transformation list and notify our listeners.
- */
- @Override
- protected void listChanged(ListChangeEvent event) {
- this.rebuildTransformedList();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java
deleted file mode 100644
index ba878e5c19..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationPropertyValueModel.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.Transformer;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * A <code>TransformationPropertyValueModel</code> wraps another
- * <code>PropertyValueModel</code> and uses a <code>Transformer</code>
- * to transform the wrapped value before it is returned by <code>value()</code>.
- * <p>
- * As an alternative to building a <code>Transformer</code>,
- * a subclass of <code>TransformationPropertyValueModel</code> can
- * either override the <code>transform_(Object)</code> method or,
- * if something other than null should be returned when the wrapped value
- * is null, override the <code>transform(Object)</code> method.
- */
-public class TransformationPropertyValueModel<T1, T2>
- extends PropertyValueModelWrapper<T1>
- implements PropertyValueModel<T2>
-{
- protected final Transformer<T1, T2> transformer;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a property value model with the specified nested
- * property value model and the default transformer.
- * Use this constructor if you want to override the
- * <code>transform_(Object)</code> or <code>transform(Object)</code>
- * method instead of building a <code>Transformer</code>.
- */
- public TransformationPropertyValueModel(PropertyValueModel<? extends T1> valueHolder) {
- super(valueHolder);
- this.transformer = this.buildTransformer();
- }
-
- /**
- * Construct an property value model with the specified nested
- * property value model and transformer.
- */
- public TransformationPropertyValueModel(PropertyValueModel<? extends T1> valueHolder, Transformer<T1, T2> transformer) {
- super(valueHolder);
- this.transformer = transformer;
- }
-
- protected Transformer<T1, T2> buildTransformer() {
- return new DefaultTransformer();
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- public T2 getValue() {
- // transform the object returned by the nested value model before returning it
- return this.transform(this.valueHolder.getValue());
- }
-
-
- // ********** PropertyValueModelWrapper implementation **********
-
- @Override
- protected void valueChanged(PropertyChangeEvent event) {
- // transform the values before propagating the change event
- @SuppressWarnings("unchecked")
- Object oldValue = this.transformOld((T1) event.getOldValue());
- @SuppressWarnings("unchecked")
- Object newValue = this.transformNew((T1) event.getNewValue());
- this.firePropertyChanged(VALUE, oldValue, newValue);
- }
-
-
- // ********** behavior **********
-
- /**
- * Transform the specified value and return the result.
- * This is called by #value() and #valueChanged(PropertyChangeEvent).
- */
- protected T2 transform(T1 value) {
- return this.transformer.transform(value);
- }
-
- /**
- * Transform the specified, non-null, value and return the result.
- */
- protected T2 transform_(@SuppressWarnings("unused") T1 value) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Transform the specified old value and return the result.
- * By default, call {@link #transform(Object)}.
- * This is called by {@link #valueChanged(PropertyChangeEvent)}.
- */
- protected T2 transformOld(T1 value) {
- return this.transform(value);
- }
-
- /**
- * Transform the specified new value and return the result.
- * By default, call {@link #transform(Object)}.
- * This is called by {@link #valueChanged(PropertyChangeEvent)}.
- */
- protected T2 transformNew(T1 value) {
- return this.transform(value);
- }
-
- // ********** default transformer **********
-
- /**
- * The default transformer will return null if the wrapped value is null.
- * If the wrapped value is not null, it is transformed by a subclass
- * implementation of #transform_(Object).
- */
- protected class DefaultTransformer implements Transformer<T1, T2> {
- public T2 transform(T1 value) {
- return (value == null) ? null : TransformationPropertyValueModel.this.transform_(value);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java
deleted file mode 100644
index 1299097bf7..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TransformationWritablePropertyValueModel.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.BidiTransformer;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * A <code>TransformationWritablePropertyValueModel</code> wraps another
- * <code>WritablePropertyValueModel</code> and uses a <code>BidiTransformer</code>
- * to:<ul>
- * <li>transform the wrapped value before it is returned by <code>value()</code>
- * <li>"reverse-transform" the new value that comes in via
- * <code>setValue(Object)</code>
- * </ul>
- * As an alternative to building a <code>BidiTransformer</code>,
- * a subclass of <code>TransformationWritablePropertyValueModel</code> can
- * override the <code>transform_(Object)</code> and
- * <code>reverseTransform_(Object)</code> methods; or,
- * if something other than null should be returned when the wrapped value
- * is null or the new value is null, override the <code>transform(Object)</code>
- * and <code>reverseTransform(Object)</code> methods.
- */
-public class TransformationWritablePropertyValueModel<T1, T2>
- extends TransformationPropertyValueModel<T1, T2>
- implements WritablePropertyValueModel<T2>
-{
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a writable property value model with the specified nested
- * writable property value model and the default bidi transformer.
- * Use this constructor if you want to override the
- * <code>transform_(Object)</code> and <code>reverseTransform_(Object)</code>
- * (or <code>transform(Object)</code> and <code>reverseTransform(Object)</code>)
- * methods instead of building a <code>BidiTransformer</code>.
- */
- public TransformationWritablePropertyValueModel(WritablePropertyValueModel<T1> valueHolder) {
- super(valueHolder);
- }
-
- /**
- * Construct a writable property value model with the specified nested
- * writable property value model and bidi transformer.
- */
- public TransformationWritablePropertyValueModel(WritablePropertyValueModel<T1> valueHolder, BidiTransformer<T1, T2> transformer) {
- super(valueHolder, transformer);
- }
-
- @Override
- protected BidiTransformer<T1, T2> buildTransformer() {
- return new DefaultBidiTransformer();
- }
-
-
- // ********** WritablePropertyValueModel implementation **********
-
- public void setValue(T2 value) {
- // "reverse-transform" the object before passing it to the the nested value model
- this.valueHolder().setValue(this.reverseTransform(value));
- }
-
-
- // ********** behavior **********
-
- /**
- * "Reverse-transform" the specified value and return the result.
- * This is called by #setValue(Object).
- */
- protected T1 reverseTransform(T2 value) {
- return this.transformer().reverseTransform(value);
- }
-
- /**
- * "Reverse-transform" the specified, non-null, value and return the result.
- */
- protected T1 reverseTransform_(@SuppressWarnings("unused") T2 value) {
- throw new UnsupportedOperationException();
- }
-
-
- // ********** queries **********
-
- /**
- * Our constructors accept only a WritablePropertyValueModel<T1>.
- */
- @SuppressWarnings("unchecked")
- protected WritablePropertyValueModel<T1> valueHolder() {
- return (WritablePropertyValueModel<T1>) this.valueHolder;
- }
-
- /**
- * Our constructors accept only a bidirectional transformer.
- */
- protected BidiTransformer<T1, T2> transformer() {
- return (BidiTransformer<T1, T2>) this.transformer;
- }
-
-
- // ********** default bidi transformer **********
-
- /**
- * The default bidi transformer will return null if the wrapped value is null.
- * If the wrapped value is not null, it is transformed by a subclass
- * implementation of #transform_(Object).
- * The default bidi transformer will also return null if the new value is null.
- * If the new value is not null, it is reverse-transformed by a subclass
- * implementation of #reverseTransform_(Object).
- */
- protected class DefaultBidiTransformer
- extends DefaultTransformer
- implements BidiTransformer<T1, T2>
- {
- public T1 reverseTransform(T2 value) {
- return (value == null) ? null : TransformationWritablePropertyValueModel.this.reverseTransform_(value);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java
deleted file mode 100644
index 739bb97012..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreeAspectAdapter.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.internal.iterators.EmptyIterator;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.TreeValueModel;
-
-/**
- * This extension of PropertyAdapter provides TreeChange support.
- * This allows us to convert a set of one or more trees into
- * a single tree, NODES.
- *
- * The typical subclass will override the following methods:
- * #nodes_()
- * at the very minimum, override this method to return an iterator
- * on the subject's tree aspect; it does not need to be overridden if
- * #nodes() is overridden and its behavior changed
- * #nodes()
- * override this method only if returning an empty iterator when the
- * subject is null is unacceptable
- */
-public abstract class TreeAspectAdapter<S extends Model, E>
- extends AspectAdapter<S>
- implements TreeValueModel<E>
-{
- /**
- * The name of the subject's trees that we use for the value.
- */
- protected final String[] treeNames;
- protected static final String[] EMPTY_TREE_NAMES = new String[0];
-
- /** A listener that listens to the subject's tree aspect. */
- protected final TreeChangeListener treeChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a TreeAspectAdapter for the specified subject
- * and tree.
- */
- protected TreeAspectAdapter(String treeName, S subject) {
- this(new String[] {treeName}, subject);
- }
-
- /**
- * Construct a TreeAspectAdapter for the specified subject
- * and trees.
- */
- protected TreeAspectAdapter(String[] treeNames, S subject) {
- this(new StaticPropertyValueModel<S>(subject), treeNames);
- }
-
- /**
- * Construct a TreeAspectAdapter for the specified subject holder
- * and trees.
- */
- protected TreeAspectAdapter(PropertyValueModel<? extends S> subjectHolder, String... treeNames) {
- super(subjectHolder);
- this.treeNames = treeNames;
- this.treeChangeListener = this.buildTreeChangeListener();
- }
-
- /**
- * Construct a TreeAspectAdapter for the specified subject holder
- * and trees.
- */
- protected TreeAspectAdapter(PropertyValueModel<? extends S> subjectHolder, Collection<String> treeNames) {
- this(subjectHolder, treeNames.toArray(new String[treeNames.size()]));
- }
-
- /**
- * Construct a TreeAspectAdapter for an "unchanging" tree in
- * the specified subject. This is useful for a tree aspect that does not
- * change for a particular subject; but the subject will change, resulting in
- * a new tree.
- */
- protected TreeAspectAdapter(PropertyValueModel<? extends S> subjectHolder) {
- this(subjectHolder, EMPTY_TREE_NAMES);
- }
-
-
- // ********** initialization **********
-
- /**
- * The subject's tree aspect has changed, notify the listeners.
- */
- protected TreeChangeListener buildTreeChangeListener() {
- // transform the subject's tree change events into VALUE tree change events
- return new TreeChangeListener() {
- public void nodeAdded(TreeChangeEvent event) {
- TreeAspectAdapter.this.nodeAdded(event);
- }
- public void nodeRemoved(TreeChangeEvent event) {
- TreeAspectAdapter.this.nodeRemoved(event);
- }
- public void treeCleared(TreeChangeEvent event) {
- TreeAspectAdapter.this.treeCleared(event);
- }
- public void treeChanged(TreeChangeEvent event) {
- TreeAspectAdapter.this.treeChanged(event);
- }
- @Override
- public String toString() {
- return "tree change listener: " + Arrays.asList(TreeAspectAdapter.this.treeNames);
- }
- };
- }
-
-
- // ********** TreeValueModel implementation **********
-
- /**
- * Return the nodes of the subject's tree aspect.
- */
- public Iterator<E> nodes() {
- return (this.subject == null) ? EmptyIterator.<E>instance() : this.nodes_();
- }
-
- /**
- * Return the nodes of the subject's tree aspect.
- * At this point we can be sure that the subject is not null.
- * @see #nodes()
- */
- protected Iterator<E> nodes_() {
- throw new UnsupportedOperationException();
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Object getValue() {
- return this.nodes();
- }
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return TreeChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return NODES;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyTreeChangeListeners(NODES);
- }
-
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.fireTreeChanged(NODES);
- }
-
- @Override
- protected void engageSubject_() {
- for (String treeName : this.treeNames) {
- ((Model) this.subject).addTreeChangeListener(treeName, this.treeChangeListener);
- }
- }
-
- @Override
- protected void disengageSubject_() {
- for (String treeName : this.treeNames) {
- ((Model) this.subject).removeTreeChangeListener(treeName, this.treeChangeListener);
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- for (int i = 0; i < this.treeNames.length; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(this.treeNames[i]);
- }
- }
-
-
- // ********** behavior **********
-
- protected void nodeAdded(TreeChangeEvent event) {
- this.fireNodeAdded(NODES, event.getPath());
- }
-
- protected void nodeRemoved(TreeChangeEvent event) {
- this.fireNodeRemoved(NODES, event.getPath());
- }
-
- protected void treeCleared(TreeChangeEvent event) {
- this.fireTreeCleared(NODES);
- }
-
- protected void treeChanged(TreeChangeEvent event) {
- this.fireTreeChanged(NODES, event.getPath());
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java
deleted file mode 100644
index 11b6f1a2b9..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/TreePropertyValueModelAdapter.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-import org.eclipse.jpt.utility.model.value.TreeValueModel;
-
-/**
- * This abstract class provides the infrastructure needed to wrap
- * a tree value model, "lazily" listen to it, and convert
- * its change notifications into property value model change
- * notifications.
- *
- * Subclasses must override:
- * - #buildValue()
- * to return the current property value, as derived from the
- * current collection value
- *
- * Subclasses might want to override:
- * - #stateChanged(StateChangeEvent event)
- * to improve performance (by not recalculating the value, if possible)
- */
-public abstract class TreePropertyValueModelAdapter<T>
- extends AspectPropertyValueModelAdapter<T>
-{
- /** The wrapped tree value model. */
- protected final TreeValueModel<?> treeHolder;
-
- /** A listener that allows us to synch with changes to the wrapped tree holder. */
- protected final TreeChangeListener treeChangeListener;
-
-
- // ********** constructor/initialization **********
-
- /**
- * Construct a property value model with the specified wrapped
- * tree value model.
- */
- protected TreePropertyValueModelAdapter(TreeValueModel<?> treeHolder) {
- super();
- this.treeHolder = treeHolder;
- this.treeChangeListener = this.buildTreeChangeListener();
- }
-
- protected TreeChangeListener buildTreeChangeListener() {
- return new TreeChangeListener() {
- public void nodeAdded(TreeChangeEvent event) {
- TreePropertyValueModelAdapter.this.nodeAdded(event);
- }
- public void nodeRemoved(TreeChangeEvent event) {
- TreePropertyValueModelAdapter.this.nodeRemoved(event);
- }
- public void treeCleared(TreeChangeEvent event) {
- TreePropertyValueModelAdapter.this.treeCleared(event);
- }
- public void treeChanged(TreeChangeEvent event) {
- TreePropertyValueModelAdapter.this.treeChanged(event);
- }
- @Override
- public String toString() {
- return "tree change listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the tree holder.
- */
- @Override
- protected void engageModel_() {
- this.treeHolder.addTreeChangeListener(this.treeChangeListener);
- }
-
- /**
- * Stop listening to the tree holder.
- */
- @Override
- protected void disengageModel_() {
- this.treeHolder.removeTreeChangeListener(this.treeChangeListener);
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.treeHolder);
- }
-
-
- // ********** state change support **********
-
- /**
- * Nodes were added to the wrapped tree holder;
- * propagate the change notification appropriately.
- */
- protected void nodeAdded(TreeChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * Nodes were removed from the wrapped tree holder;
- * propagate the change notification appropriately.
- */
- protected void nodeRemoved(TreeChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The wrapped tree holder was cleared;
- * propagate the change notification appropriately.
- */
- protected void treeCleared(TreeChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
- /**
- * The wrapped tree holder changed;
- * propagate the change notification appropriately.
- */
- protected void treeChanged(TreeChangeEvent event) {
- // by default, simply recalculate the value and fire an event
- this.propertyChanged();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java
deleted file mode 100644
index 6fea2e865f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueAspectAdapter.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Abstract model that provides behavior for wrapping a property
- * value model and listening for changes to aspects of the *value* contained
- * by the property value model. Changes to the actual value are also monitored.
- *
- * This is useful if you have a value that may change, but whose aspects can also
- * change in a fashion that might be of interest to the client.
- *
- * NB: Clients will need to listen for two different change notifications: a property
- * change event will be be fired when the value changes; a state change event
- * will be fired when an aspect of the value changes.
- *
- * Subclasses need to override two methods:
- *
- * #engageValue_()
- * begin listening to the appropriate aspect of the value and call
- * #valueAspectChanged(Object) whenever the aspect changes
- *
- * #disengageValue_()
- * stop listening to the appropriate aspect of the value
- */
-public abstract class ValueAspectAdapter<T>
- extends PropertyValueModelWrapper<T>
- implements WritablePropertyValueModel<T>
-{
- /** Cache the value so we can disengage. Null until we have a listener*/
- protected T value;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Constructor - the value holder is required.
- */
- protected ValueAspectAdapter(WritablePropertyValueModel<T> valueHolder) {
- super(valueHolder);
- }
-
- /**
- * Override to allow both property value model change and state change
- * listeners.
- */
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new ChangeSupport(this);
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- public T getValue() {
- return this.value;
- }
-
-
- // ********** WritablePropertyValueModel implementation **********
-
- public void setValue(T value) {
- this.valueHolder().setValue(value);
- }
-
-
- // ********** PropertyValueModelWrapper implementation **********
-
- @Override
- protected void valueChanged(PropertyChangeEvent event) {
- this.disengageValue();
- this.engageValue();
- this.firePropertyChanged(event.cloneWithSource(this));
- }
-
-
- // ********** extend change support **********
-
- @Override
- public synchronized void addStateChangeListener(StateChangeListener listener) {
- if (this.hasNoStateChangeListeners()) {
- this.engageValue();
- }
- super.addStateChangeListener(listener);
- }
-
- @Override
- public synchronized void removeStateChangeListener(StateChangeListener listener) {
- super.removeStateChangeListener(listener);
- if (this.hasNoStateChangeListeners()) {
- this.disengageValue();
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the current value.
- */
- protected void engageValue() {
- this.value = this.valueHolder.getValue();
- if (this.value != null) {
- this.engageValue_();
- }
- }
-
- /**
- * Start listening to the current value.
- * At this point we can be sure that the value is not null.
- */
- protected abstract void engageValue_();
-
- /**
- * Stop listening to the current value.
- */
- protected void disengageValue() {
- if (this.value != null) {
- this.disengageValue_();
- this.value = null;
- }
- }
-
- /**
- * Stop listening to the current value.
- * At this point we can be sure that the value is not null.
- */
- protected abstract void disengageValue_();
-
- /**
- * Subclasses should call this method whenever the value's aspect changes.
- */
- protected void valueAspectChanged() {
- this.fireStateChanged();
- }
-
- /**
- * Our constructors accept only a WritablePropertyValueModel<T1>.
- */
- @SuppressWarnings("unchecked")
- protected WritablePropertyValueModel<T> valueHolder() {
- return (WritablePropertyValueModel<T>) this.valueHolder;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java
deleted file mode 100644
index 069fc0e2e0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueCollectionAdapter.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Extend ValueAspectAdapter to listen to one or more collection
- * aspects of the value in the wrapped value model.
- */
-public class ValueCollectionAdapter<T extends Model>
- extends ValueAspectAdapter<T>
-{
-
- /** The names of the value's collections that we listen to. */
- protected final String[] collectionNames;
-
- /** Listener that listens to the value. */
- protected final CollectionChangeListener valueCollectionListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified value collections.
- */
- public ValueCollectionAdapter(WritablePropertyValueModel<T> valueHolder, String... collectionNames) {
- super(valueHolder);
- this.collectionNames = collectionNames;
- this.valueCollectionListener = this.buildValueCollectionListener();
- }
-
-
- // ********** initialization **********
-
- /**
- * All we really care about is the fact that a Collection aspect has
- * changed. Do the same thing no matter which event occurs.
- */
- protected CollectionChangeListener buildValueCollectionListener() {
- return new CollectionChangeListener() {
- public void itemsAdded(CollectionChangeEvent event) {
- ValueCollectionAdapter.this.valueAspectChanged();
- }
- public void itemsRemoved(CollectionChangeEvent event) {
- ValueCollectionAdapter.this.valueAspectChanged();
- }
- public void collectionCleared(CollectionChangeEvent event) {
- ValueCollectionAdapter.this.valueAspectChanged();
- }
- public void collectionChanged(CollectionChangeEvent event) {
- ValueCollectionAdapter.this.valueAspectChanged();
- }
- @Override
- public String toString() {
- return "value collection listener: " + Arrays.asList(ValueCollectionAdapter.this.collectionNames);
- }
- };
- }
-
- @Override
- protected void engageValue_() {
- for (String collectionName : this.collectionNames) {
- this.value.addCollectionChangeListener(collectionName, this.valueCollectionListener);
- }
- }
-
- @Override
- protected void disengageValue_() {
- for (String collectionName : this.collectionNames) {
- this.value.removeCollectionChangeListener(collectionName, this.valueCollectionListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java
deleted file mode 100644
index 85cb429f8f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueListAdapter.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Extend ValueAspectAdapter to listen to one or more list
- * aspects of the value in the wrapped value model.
- */
-public class ValueListAdapter<T extends Model>
- extends ValueAspectAdapter<T>
-{
-
- /** The names of the value's lists that we listen to. */
- protected final String[] listNames;
-
- /** Listener that listens to the value. */
- protected final ListChangeListener valueListListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified value lists.
- */
- public ValueListAdapter(WritablePropertyValueModel<T> valueHolder, String... listNames) {
- super(valueHolder);
- this.listNames = listNames;
- this.valueListListener = this.buildValueListListener();
- }
-
-
- // ********** initialization **********
-
- /**
- * All we really care about is the fact that a List aspect has
- * changed. Do the same thing no matter which event occurs.
- */
- protected ListChangeListener buildValueListListener() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ValueListAdapter.this.valueAspectChanged();
- }
- public void itemsRemoved(ListChangeEvent event) {
- ValueListAdapter.this.valueAspectChanged();
- }
- public void itemsReplaced(ListChangeEvent event) {
- ValueListAdapter.this.valueAspectChanged();
- }
- public void itemsMoved(ListChangeEvent event) {
- ValueListAdapter.this.valueAspectChanged();
- }
- public void listCleared(ListChangeEvent event) {
- ValueListAdapter.this.valueAspectChanged();
- }
- public void listChanged(ListChangeEvent event) {
- ValueListAdapter.this.valueAspectChanged();
- }
- @Override
- public String toString() {
- return "value list listener: " + Arrays.asList(ValueListAdapter.this.listNames);
- }
- };
- }
-
- @Override
- protected void engageValue_() {
- for (String listName : this.listNames) {
- this.value.addListChangeListener(listName, this.valueListListener);
- }
- }
-
- @Override
- protected void disengageValue_() {
- for (String listName : this.listNames) {
- this.value.removeListChangeListener(listName, this.valueListListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java
deleted file mode 100644
index a3d7e01731..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValuePropertyAdapter.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Extend ValueAspectAdapter to listen to one or more
- * properties of the value in the wrapped value model.
- */
-public class ValuePropertyAdapter<T extends Model>
- extends ValueAspectAdapter<T>
-{
- /** The names of the value's properties that we listen to. */
- protected final String[] propertyNames;
-
- /** Listener that listens to the value. */
- protected final PropertyChangeListener valuePropertyListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified value properties.
- */
- public ValuePropertyAdapter(WritablePropertyValueModel<T> valueHolder, String... propertyNames) {
- super(valueHolder);
- this.propertyNames = propertyNames;
- this.valuePropertyListener = this.buildValuePropertyListener();
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildValuePropertyListener() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- ValuePropertyAdapter.this.valueAspectChanged();
- }
- @Override
- public String toString() {
- return "value property listener: " + Arrays.asList(ValuePropertyAdapter.this.propertyNames);
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void engageValue_() {
- for (String propertyName : this.propertyNames) {
- this.value.addPropertyChangeListener(propertyName, this.valuePropertyListener);
- }
- }
-
- @Override
- protected void disengageValue_() {
- for (String propertyName : this.propertyNames) {
- this.value.removePropertyChangeListener(propertyName, this.valuePropertyListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java
deleted file mode 100644
index d516fdbf1b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueStateAdapter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Extend ValueAspectAdapter to listen to the
- * "state" of the value in the wrapped value model.
- */
-public class ValueStateAdapter<T extends Model>
- extends ValueAspectAdapter<T>
-{
- /** Listener that listens to value. */
- protected final StateChangeListener valueStateListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the value state.
- */
- public ValueStateAdapter(WritablePropertyValueModel<T> valueHolder) {
- super(valueHolder);
- this.valueStateListener = this.buildValueStateListener();
- }
-
-
- // ********** initialization **********
-
- protected StateChangeListener buildValueStateListener() {
- return new StateChangeListener() {
- public void stateChanged(StateChangeEvent event) {
- ValueStateAdapter.this.valueAspectChanged();
- }
- @Override
- public String toString() {
- return "value state listener";
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void engageValue_() {
- this.value.addStateChangeListener(this.valueStateListener);
- }
-
- @Override
- protected void disengageValue_() {
- this.value.removeStateChangeListener(this.valueStateListener);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java
deleted file mode 100644
index 41361ed37a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/ValueTreeAdapter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.model.Model;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * Extend ValueAspectAdapter to listen to one or more
- * tree aspects of the value in the wrapped value model.
- */
-public class ValueTreeAdapter<T extends Model>
- extends ValueAspectAdapter<T>
-{
- /** The names of the value's trees that we listen to. */
- protected final String[] treeNames;
-
- /** Listener that listens to the value. */
- protected final TreeChangeListener valueTreeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified value trees.
- */
- public ValueTreeAdapter(WritablePropertyValueModel<T> valueHolder, String... treeNames) {
- super(valueHolder);
- this.treeNames = treeNames;
- this.valueTreeListener = this.buildValueTreeListener();
- }
-
-
- // ********** initialization **********
-
- protected TreeChangeListener buildValueTreeListener() {
- return new TreeChangeListener() {
- public void nodeAdded(TreeChangeEvent event) {
- ValueTreeAdapter.this.valueAspectChanged();
- }
- public void nodeRemoved(TreeChangeEvent event) {
- ValueTreeAdapter.this.valueAspectChanged();
- }
- public void treeCleared(TreeChangeEvent event) {
- ValueTreeAdapter.this.valueAspectChanged();
- }
- public void treeChanged(TreeChangeEvent event) {
- ValueTreeAdapter.this.valueAspectChanged();
- }
- @Override
- public String toString() {
- return "value tree listener: " + Arrays.asList(ValueTreeAdapter.this.treeNames);
- }
- };
- }
-
-
- // ********** behavior **********
-
- @Override
- protected void engageValue_() {
- for (String treeName : this.treeNames) {
- this.value.addTreeChangeListener(treeName, this.valueTreeListener);
- }
- }
-
- @Override
- protected void disengageValue_() {
- for (String treeName : this.treeNames) {
- this.value.removeTreeChangeListener(treeName, this.valueTreeListener);
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java
deleted file mode 100644
index 44a9d56e11..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencePropertyValueModel.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.prefs;
-
-import java.util.prefs.PreferenceChangeEvent;
-import java.util.prefs.PreferenceChangeListener;
-import java.util.prefs.Preferences;
-import org.eclipse.jpt.utility.internal.BidiStringConverter;
-import org.eclipse.jpt.utility.internal.model.value.AspectAdapter;
-import org.eclipse.jpt.utility.internal.model.value.StaticPropertyValueModel;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This adapter wraps a Preference and converts it into a PropertyValueModel.
- * It listens for the appropriate "preference" changes and converts them into
- * VALUE property changes. It also allows the specification of a default value
- * for the Preference, which, by default, is null (and is probably *not* a very
- * good default).
- *
- * You can configure whether the preference's value is returned,
- * unchanged, as a string or as some other object (e.g. an Integer) by
- * setting the adapter's converter. Internally, the preference's value
- * is stored as the converted object; and the conversions take place
- * when reading or writing from the preferences node or retrieving the
- * value from an event fired by the preferences node.
- *
- * This adapter is a bit different from most other adapters because the
- * change events fired off by a Preferences node are asynchronous from
- * the change itself. (AbstractPreferences uses an event dispatch daemon.)
- * As a result, a client can set our value with #setValue(Object) and we
- * will return from that method before we ever receive notification from
- * the Preferences node that *it* has changed. This means we cannot
- * rely on that event to keep our internally cached value in synch.
- */
-public class PreferencePropertyValueModel<P>
- extends AspectAdapter<Preferences>
- implements WritablePropertyValueModel<P>
-{
- /** The key to the preference we use for the value. */
- protected final String key;
-
- /**
- * Cache the current (object) value of the preference so we
- * can pass an "old value" when we fire a property change event.
- */
- protected P value;
-
- /**
- * The default (object) value returned if there is no value
- * associated with the preference.
- */
- protected final P defaultValue;
-
- /**
- * This converter is used to convert the preference's
- * string value to and from an object.
- */
- protected final BidiStringConverter<P> converter;
-
- /** A listener that listens to the appropriate preference. */
- protected final PreferenceChangeListener preferenceChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified preference.
- * The default value of the preference will be null.
- */
- public PreferencePropertyValueModel(Preferences preferences, String key) {
- this(preferences, key, null);
- }
-
- /**
- * Construct an adapter for the specified preference with
- * the specified default value for the preference.
- */
- public PreferencePropertyValueModel(Preferences preferences, String key, P defaultValue) {
- this(preferences, key, defaultValue, BidiStringConverter.Default.<P>instance());
- }
-
- /**
- * Construct an adapter for the specified preference with
- * the specified default value for the preference.
- */
- public PreferencePropertyValueModel(Preferences preferences, String key, P defaultValue, BidiStringConverter<P> converter) {
- this(new StaticPropertyValueModel<Preferences>(preferences), key, defaultValue, converter);
- }
-
- /**
- * Construct an adapter for the specified preference with
- * the specified default value for the preference.
- */
- public static PreferencePropertyValueModel<Boolean> forBoolean(Preferences preferences, String key, boolean defaultValue) {
- return new PreferencePropertyValueModel<Boolean>(
- preferences,
- key,
- defaultValue ? Boolean.TRUE : Boolean.FALSE,
- BidiStringConverter.BooleanConverter.instance()
- );
- }
-
- /**
- * Construct an adapter for the specified preference with
- * the specified default value for the preference.
- */
- public static PreferencePropertyValueModel<Integer> forInteger(Preferences preferences, String key, int defaultValue) {
- return new PreferencePropertyValueModel<Integer>(
- preferences,
- key,
- new Integer(defaultValue),
- BidiStringConverter.IntegerConverter.instance()
- );
- }
-
- /**
- * Construct an adapter for the specified preference.
- * The default value of the preference will be null.
- */
- public PreferencePropertyValueModel(PropertyValueModel<? extends Preferences> preferencesHolder, String key) {
- this(preferencesHolder, key, null);
- }
-
- /**
- * Construct an adapter for the specified preference with
- * the specified default value for the preference.
- */
- public PreferencePropertyValueModel(PropertyValueModel<? extends Preferences> preferencesHolder, String key, P defaultValue) {
- this(preferencesHolder, key, defaultValue, BidiStringConverter.Default.<P>instance());
- }
-
- /**
- * Construct an adapter for the specified preference with
- * the specified default value for the preference.
- */
- public PreferencePropertyValueModel(PropertyValueModel<? extends Preferences> preferencesHolder, String key, P defaultValue, BidiStringConverter<P> converter) {
- super(preferencesHolder);
- this.key = key;
- this.defaultValue = defaultValue;
- this.converter = converter;
- this.preferenceChangeListener = this.buildPreferenceChangeListener();
- // our value is null when we are not listening to the preference
- this.value = null;
- }
-
-
- // ********** initialization **********
-
- /**
- * A preference has changed, notify the listeners if necessary.
- */
- protected PreferenceChangeListener buildPreferenceChangeListener() {
- // transform the preference change events into VALUE property change events
- return new PreferenceChangeListener() {
- public void preferenceChange(PreferenceChangeEvent event) {
- PreferencePropertyValueModel.this.preferenceChanged(event.getKey(), event.getNewValue());
- }
- @Override
- public String toString() {
- return "preference change listener";
- }
- };
- }
-
-
- // ********** ValueModel implementation **********
-
- /**
- * Return the cached (converted) value.
- */
- @Override
- public synchronized P getValue() {
- return this.value;
- }
-
-
- // ********** PropertyValueModel implementation **********
-
- /**
- * Set the cached value, then set the appropriate preference value.
- */
- public synchronized void setValue(P value) {
- if (this.hasNoListeners()) {
- return; // no changes allowed when we have no listeners
- }
-
- Object old = this.value;
- this.value = value;
- this.fireAspectChange(old, value);
-
- if ((this.subject != null) && this.shouldSetPreference(old, value)) {
- this.setValue_(value);
- }
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return PropertyChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return VALUE;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyPropertyChangeListeners(VALUE);
- }
-
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.firePropertyChanged(VALUE, oldValue, newValue);
- }
-
- @Override
- protected void engageSubject_() {
- this.subject.addPreferenceChangeListener(this.preferenceChangeListener);
- this.value = this.buildValue();
- }
-
- @Override
- protected void disengageSubject_() {
- try {
- this.subject.removePreferenceChangeListener(this.preferenceChangeListener);
- } catch (IllegalStateException ex) {
- // for some odd reason, we are not allowed to remove a listener from a "dead"
- // preferences node; so handle the exception that gets thrown here
- if ( ! ex.getMessage().equals("Node has been removed.")) {
- // if it is not the expected exception, re-throw it
- throw ex;
- }
- }
- this.value = null;
- }
-
-
- // ********** AbstractModel implementation **********
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.key);
- sb.append(" => ");
- sb.append(this.value);
- }
-
-
- // ********** public API **********
-
- /**
- * Return the preference's key.
- */
- public String getKey() {
- return this.key;
- }
-
-
- // ********** internal methods **********
-
- /**
- * Return the preference's value.
- * At this point the subject may be null.
- */
- protected P buildValue() {
- return (this.subject == null) ? null : this.buildValue_();
- }
-
- /**
- * Return the appropriate preference, converted to the appropriate object.
- * At this point we can be sure that the subject is not null.
- */
- protected P buildValue_() {
- return this.convertToObject(this.subject.get(this.key, this.convertToString(this.defaultValue)));
- }
-
- /**
- * Set the appropriate preference after converting the value to a string.
- * At this point we can be sure that the subject is not null.
- */
- protected void setValue_(P value) {
- this.subject.put(this.key, this.convertToString(value));
- }
-
- /**
- * Return whether the specified new value should be passed
- * through to the preference. By default, only if the value has changed,
- * will it be passed through to the preference. This also has the
- * effect of not creating new preferences in the "backing store"
- * if the new value is the same as the default value.
- *
- * Subclasses can override this method to return true if they
- * would like to ALWAYS pass through the new value to the preference.
- */
- protected boolean shouldSetPreference(Object oldValue, Object newValue) {
- return this.attributeValueHasChanged(oldValue, newValue);
- }
-
- /**
- * Convert the specified object to a string that can be stored as
- * the value of the preference.
- */
- protected String convertToString(P o) {
- return this.converter.convertToString(o);
- }
-
- /**
- * Convert the specified preference value string to an
- * appropriately-typed object to be returned to the client.
- */
- protected P convertToObject(String s) {
- return this.converter.convertToObject(s);
- }
-
- protected void preferenceChanged(String prefKey, String newValue) {
- if (prefKey.equals(this.key)) {
- this.preferenceChanged();
- }
- }
-
- /**
- * The underlying preference changed; either because we changed it
- * in #setValue_(Object) or a third-party changed it.
- * If this is called because of our own change, the event will be
- * swallowed because the old and new values are the same.
- */
- protected synchronized void preferenceChanged() {
- Object old = this.value;
- this.value = this.buildValue();
- this.fireAspectChange(old, this.value);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java
deleted file mode 100644
index 546a6686d2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.prefs;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.prefs.BackingStoreException;
-import java.util.prefs.PreferenceChangeEvent;
-import java.util.prefs.PreferenceChangeListener;
-import java.util.prefs.Preferences;
-import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
-import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
-import org.eclipse.jpt.utility.internal.model.value.AspectAdapter;
-import org.eclipse.jpt.utility.internal.model.value.StaticPropertyValueModel;
-import org.eclipse.jpt.utility.model.listener.ChangeListener;
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-
-/**
- * This adapter wraps a Preferences node and converts its preferences into a
- * CollectionValueModel of PreferencePropertyValueModels. It listens for
- * "preference" changes and converts them into VALUE collection changes.
- */
-public class PreferencesCollectionValueModel<P>
- extends AspectAdapter<Preferences>
- implements CollectionValueModel<PreferencePropertyValueModel<P>>
-{
-
- /** Cache the current preferences, stored in models and keyed by name. */
- protected final HashMap<String, PreferencePropertyValueModel<P>> preferences;
-
- /** A listener that listens to the preferences node for added or removed preferences. */
- protected final PreferenceChangeListener preferenceChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct an adapter for the specified preferences node.
- */
- public PreferencesCollectionValueModel(Preferences preferences) {
- this(new StaticPropertyValueModel<Preferences>(preferences));
- }
-
- /**
- * Construct an adapter for the specified preferences node.
- */
- public PreferencesCollectionValueModel(PropertyValueModel<? extends Preferences> preferencesHolder) {
- super(preferencesHolder);
- this.preferences = new HashMap<String, PreferencePropertyValueModel<P>>();
- this.preferenceChangeListener = this.buildPreferenceChangeListener();
- }
-
-
- // ********** initialization **********
-
- /**
- * A preferences have changed, notify the listeners.
- */
- protected PreferenceChangeListener buildPreferenceChangeListener() {
- // transform the preference change events into VALUE collection change events
- return new PreferenceChangeListener() {
- public void preferenceChange(PreferenceChangeEvent event) {
- PreferencesCollectionValueModel.this.preferenceChanged(event.getKey(), event.getNewValue());
- }
- @Override
- public String toString() {
- return "preference change listener";
- }
- };
- }
-
-
- // ********** CollectionValueModel implementation **********
-
- /**
- * Return an iterator on the preference models.
- */
- public synchronized Iterator<PreferencePropertyValueModel<P>> iterator() {
- return this.preferences.values().iterator();
- }
-
- public synchronized int size() {
- return this.preferences.size();
- }
-
-
- // ********** AspectAdapter implementation **********
-
- @Override
- protected Object getValue() {
- return this.iterator();
- }
-
- @Override
- protected Class<? extends ChangeListener> getListenerClass() {
- return CollectionChangeListener.class;
- }
-
- @Override
- protected String getListenerAspectName() {
- return VALUES;
- }
-
- @Override
- protected boolean hasListeners() {
- return this.hasAnyCollectionChangeListeners(VALUES);
- }
-
- @Override
- protected void fireAspectChange(Object oldValue, Object newValue) {
- this.fireCollectionChanged(VALUES);
- }
-
- @Override
- protected void engageSubject_() {
- this.subject.addPreferenceChangeListener(this.preferenceChangeListener);
- for (Iterator<PreferencePropertyValueModel<P>> stream = this.preferenceModels(); stream.hasNext(); ) {
- PreferencePropertyValueModel<P> preferenceModel = stream.next();
- this.preferences.put(preferenceModel.getKey(), preferenceModel);
- }
- }
-
- @Override
- protected void disengageSubject_() {
- try {
- this.subject.removePreferenceChangeListener(this.preferenceChangeListener);
- } catch (IllegalStateException ex) {
- // for some odd reason, we are not allowed to remove a listener from a "dead"
- // preferences node; so handle the exception that gets thrown here
- if ( ! ex.getMessage().equals("Node has been removed.")) {
- // if it is not the expected exception, re-throw it
- throw ex;
- }
- }
- this.preferences.clear();
- }
-
-
- // ********** AbstractModel implementation **********
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.subject);
- }
-
-
- // ********** internal methods **********
-
- /**
- * Return an iterator on the preference models.
- * At this point we can be sure that the subject is not null.
- */
- protected Iterator<PreferencePropertyValueModel<P>> preferenceModels() {
- String[] keys;
- try {
- keys = this.subject.keys();
- } catch (BackingStoreException ex) {
- throw new RuntimeException(ex);
- }
- return new TransformationIterator<String, PreferencePropertyValueModel<P>>(new ArrayIterator<String>(keys)) {
- @Override
- protected PreferencePropertyValueModel<P> transform(String key) {
- return PreferencesCollectionValueModel.this.buildPreferenceModel(key);
- }
- };
- }
-
- /**
- * Override this method to tweak the model used to wrap the
- * specified preference (e.g. to customize the model's converter).
- */
- protected PreferencePropertyValueModel<P> buildPreferenceModel(String key) {
- return new PreferencePropertyValueModel<P>(this.subjectHolder, key);
- }
-
- protected synchronized void preferenceChanged(String key, String newValue) {
- if (newValue == null) {
- // a preference was removed
- PreferencePropertyValueModel<P> preferenceModel = this.preferences.remove(key);
- this.fireItemRemoved(VALUES, preferenceModel);
- } else if ( ! this.preferences.containsKey(key)) {
- // a preference was added
- PreferencePropertyValueModel<P> preferenceModel = this.buildPreferenceModel(key);
- this.preferences.put(key, preferenceModel);
- this.fireItemAdded(VALUES, preferenceModel);
- } else {
- // a preference's value changed - do nothing
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java
deleted file mode 100644
index 302a83f1dd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/AbstractTreeModel.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.io.Serializable;
-import javax.swing.event.EventListenerList;
-import javax.swing.event.TreeModelEvent;
-import javax.swing.event.TreeModelListener;
-import javax.swing.tree.TreeModel;
-
-/**
- * Abstract class that should have been provided by the JDK
- * ( la javax.swing.AbstractListModel). This class provides:
- * - support for a collection of listeners
- * - a number of convenience methods for firing events for those listeners
- */
-public abstract class AbstractTreeModel
- implements TreeModel, Serializable
-{
- /** Our listeners. */
- protected final EventListenerList listenerList;
-
-
- // ********** constructors/initialization **********
-
- protected AbstractTreeModel() {
- super();
- this.listenerList = new EventListenerList();
- }
-
-
- // ********** partial TreeModel implementation **********
-
- public void addTreeModelListener(TreeModelListener l) {
- this.listenerList.add(TreeModelListener.class, l);
- }
-
- public void removeTreeModelListener(TreeModelListener l) {
- this.listenerList.remove(TreeModelListener.class, l);
- }
-
-
- // ********** queries **********
-
- /**
- * Return the model's current collection of listeners.
- * (There seems to be a pattern of making this type of method public;
- * although it should probably be protected....)
- */
- public TreeModelListener[] treeModelListeners() {
- return this.listenerList.getListeners(TreeModelListener.class);
- }
-
- /**
- * Return whether this model has no listeners.
- */
- protected boolean hasNoTreeModelListeners() {
- return this.listenerList.getListenerCount(TreeModelListener.class) == 0;
- }
-
- /**
- * Return whether this model has any listeners.
- */
- protected boolean hasTreeModelListeners() {
- return ! this.hasNoTreeModelListeners();
- }
-
-
- // ********** behavior **********
-
- /**
- * Notify listeners of a model change.
- * A significant property of the nodes changed, but the nodes themselves
- * are still the same objects.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeNodesChanged(Object[] path, int[] childIndices, Object[] children) {
- // guaranteed to return a non-null array
- Object[] listeners = this.listenerList.getListenerList();
- TreeModelEvent event = null;
- // process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length-2; i>=0; i-=2) {
- if (listeners[i]==TreeModelListener.class) {
- // lazily create the event
- if (event == null) {
- event = new TreeModelEvent(this, path, childIndices, children);
- }
- ((TreeModelListener) listeners[i+1]).treeNodesChanged(event);
- }
- }
- }
-
-
- /**
- * Notify listeners of a model change.
- * A significant property of the node changed, but the node itself is the same object.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeNodeChanged(Object[] path, int childIndex, Object child) {
- this.fireTreeNodesChanged(path, new int[] {childIndex}, new Object[] {child});
- }
-
- /**
- * Notify listeners of a model change.
- * A significant property of the root changed, but the root itself is the same object.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeRootChanged(Object root) {
- this.fireTreeNodesChanged(new Object[] {root}, null, null);
- }
-
- /**
- * Notify listeners of a model change.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeNodesInserted(Object[] path, int[] childIndices, Object[] children) {
- // guaranteed to return a non-null array
- Object[] listeners = this.listenerList.getListenerList();
- TreeModelEvent event = null;
- // process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length-2; i>=0; i-=2) {
- if (listeners[i]==TreeModelListener.class) {
- // lazily create the event
- if (event == null) {
- event = new TreeModelEvent(this, path, childIndices, children);
- }
- ((TreeModelListener) listeners[i+1]).treeNodesInserted(event);
- }
- }
- }
-
- /**
- * Notify listeners of a model change.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeNodeInserted(Object[] path, int childIndex, Object child) {
- this.fireTreeNodesInserted(path, new int[] {childIndex}, new Object[] {child});
- }
-
- /**
- * Notify listeners of a model change.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeNodesRemoved(Object[] path, int[] childIndices, Object[] children) {
- // guaranteed to return a non-null array
- Object[] listeners = this.listenerList.getListenerList();
- TreeModelEvent event = null;
- // process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length-2; i>=0; i-=2) {
- if (listeners[i]==TreeModelListener.class) {
- // lazily create the event
- if (event == null) {
- event = new TreeModelEvent(this, path, childIndices, children);
- }
- ((TreeModelListener) listeners[i+1]).treeNodesRemoved(event);
- }
- }
- }
-
- /**
- * Notify listeners of a model change.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeNodeRemoved(Object[] path, int childIndex, Object child) {
- this.fireTreeNodesRemoved(path, new int[] {childIndex}, new Object[] {child});
- }
-
- /**
- * Notify listeners of a model change.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeStructureChanged(Object[] path) {
- // guaranteed to return a non-null array
- Object[] listeners = this.listenerList.getListenerList();
- TreeModelEvent event = null;
- // process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length-2; i>=0; i-=2) {
- if (listeners[i]==TreeModelListener.class) {
- // lazily create the event
- if (event == null) {
- event = new TreeModelEvent(this, path);
- }
- ((TreeModelListener) listeners[i+1]).treeStructureChanged(event);
- }
- }
- }
-
- /**
- * Notify listeners of a model change.
- * @see javax.swing.event.TreeModelEvent
- * @see javax.swing.event.TreeModelListener
- */
- protected void fireTreeRootReplaced(Object newRoot) {
- this.fireTreeStructureChanged(new Object[] {newRoot});
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java
deleted file mode 100644
index 126cbfa561..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/CheckBoxModelAdapter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.ButtonModel can be used to keep a listener
- * (e.g. a JCheckBox) in synch with a PropertyValueModel that
- * holds a boolean.
- *
- * Maybe not the richest class in our toolbox, but it was the
- * victim of refactoring.... ~bjv
- */
-public class CheckBoxModelAdapter
- extends ToggleButtonModelAdapter
-{
-
- // ********** constructors **********
-
- /**
- * Constructor - the boolean holder is required.
- */
- public CheckBoxModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) {
- super(booleanHolder, defaultValue);
- }
-
- /**
- * Constructor - the boolean holder is required.
- * The default value will be false.
- */
- public CheckBoxModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder) {
- super(booleanHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java
deleted file mode 100644
index 482b5d2468..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ColumnAdapter.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-
-/**
- * This adapter is used by the table model adapter to
- * convert a model object into the models used for each of
- * the cells for the object's corresponding row in the table.
- */
-public interface ColumnAdapter {
- /**
- * Return the number of columns in the table.
- * Typically this is static.
- */
- int columnCount();
-
- /**
- * Return the name of the specified column.
- */
- String columnName(int index);
-
- /**
- * Return the class of the specified column.
- */
- Class<?> columnClass(int index);
-
- /**
- * Return whether the specified column is editable.
- * Typically this is the same for every row.
- */
- boolean columnIsEditable(int index);
-
- /**
- * Return the cell models for the specified subject
- * that corresponds to a single row in the table.
- */
- WritablePropertyValueModel<Object>[] cellModels(Object subject);
-
-} \ No newline at end of file
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java
deleted file mode 100644
index b3e0c9269c..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ComboBoxModelAdapter.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import javax.swing.ComboBoxModel;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.ComboBoxModel can be used to keep a ListDataListener
- * (e.g. a JComboBox) in synch with a ListValueModel (or a CollectionValueModel).
- * For combo boxes, the model object that holds the current selection is
- * typically a different model object than the one that holds the collection
- * of choices.
- *
- * For example, a MWReference (the selectionOwner) has an attribute
- * "sourceTable" (the collectionOwner)
- * which holds on to a collection of MWDatabaseFields. When the selection
- * is changed this model will keep the listeners aware of the changes.
- * The inherited list model will keep its listeners aware of changes to the
- * collection model
- *
- * In addition to the collection holder required by the superclass,
- * an instance of this ComboBoxModel must be supplied with a
- * selection holder, which is a PropertyValueModel that provides access
- * to the selection (typically a PropertyAspectAdapter).
- */
-public class ComboBoxModelAdapter
- extends ListModelAdapter
- implements ComboBoxModel
-{
- protected final WritablePropertyValueModel<Object> selectionHolder;
- protected final PropertyChangeListener selectionListener;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the list holder and selection holder are required;
- */
- public ComboBoxModelAdapter(ListValueModel<?> listHolder, WritablePropertyValueModel<Object> selectionHolder) {
- super(listHolder);
- if (selectionHolder == null) {
- throw new NullPointerException();
- }
- this.selectionHolder = selectionHolder;
- this.selectionListener = this.buildSelectionListener();
- }
-
- /**
- * Constructor - the collection holder and selection holder are required;
- */
- public ComboBoxModelAdapter(CollectionValueModel<?> collectionHolder, WritablePropertyValueModel<Object> selectionHolder) {
- super(collectionHolder);
- if (selectionHolder == null) {
- throw new NullPointerException();
- }
- this.selectionHolder = selectionHolder;
- this.selectionListener = this.buildSelectionListener();
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildSelectionListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildSelectionListener_());
- }
-
- protected PropertyChangeListener buildSelectionListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- // notify listeners that the selection has changed
- ComboBoxModelAdapter.this.fireSelectionChanged();
- }
- @Override
- public String toString() {
- return "selection listener";
- }
- };
- }
-
-
- // ********** ComboBoxModel implementation **********
-
- public Object getSelectedItem() {
- return this.selectionHolder.getValue();
- }
-
- public void setSelectedItem(Object selectedItem) {
- this.selectionHolder.setValue(selectedItem);
- }
-
-
- // ********** behavior **********
-
- /**
- * Extend to engage the selection holder.
- */
- @Override
- protected void engageModel() {
- super.engageModel();
- this.selectionHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener);
- }
-
- /**
- * Extend to disengage the selection holder.
- */
- @Override
- protected void disengageModel() {
- this.selectionHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener);
- super.disengageModel();
- }
-
- /**
- * Notify the listeners that the selection has changed.
- */
- protected void fireSelectionChanged() {
- // I guess this will work...
- this.fireContentsChanged(this, -1, -1);
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.selectionHolder + ":" + this.listHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java
deleted file mode 100644
index 66d09d23ca..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DateSpinnerModelAdapter.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.util.Calendar;
-import java.util.Date;
-import javax.swing.SpinnerDateModel;
-import javax.swing.event.ChangeListener;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.SpinnerDateModel can be used to keep a ChangeListener
- * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a date.
- *
- * This class must be a sub-class of SpinnerDateModel because of some
- * crappy jdk code.... ~bjv
- * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
- *
- * If this class needs to be modified, it would behoove us to review the
- * other, similar classes:
- * @see ListSpinnerModelAdapter
- * @see NumberSpinnerModelAdapter
- */
-public class DateSpinnerModelAdapter
- extends SpinnerDateModel
-{
-
- /**
- * The default spinner value; used when the underlying model date value is null.
- * The default is the current date.
- */
- private final Date defaultValue;
-
- /** A value model on the underlying date. */
- private final WritablePropertyValueModel<Object> dateHolder;
-
- /** A listener that allows us to synchronize with changes made to the underlying date. */
- private final PropertyChangeListener dateChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the date holder is required.
- * The default spinner value is the current date.
- */
- public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder) {
- this(dateHolder, new Date());
- }
-
- /**
- * Constructor - the date holder and default value are required.
- */
- public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder, Date defaultValue) {
- this(dateHolder, null, null, Calendar.DAY_OF_MONTH, defaultValue);
- }
-
- /**
- * Constructor - the date holder is required.
- * The default spinner value is the current date.
- */
- public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField) {
- this(dateHolder, start, end, calendarField, new Date());
- }
-
- /**
- * Constructor - the date holder is required.
- */
- public DateSpinnerModelAdapter(WritablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField, Date defaultValue) {
- super(dateHolder.getValue() == null ? defaultValue : (Date) dateHolder.getValue(), start, end, calendarField);
- this.dateHolder = dateHolder;
- this.dateChangeListener = this.buildDateChangeListener();
- // postpone listening to the underlying date
- // until we have listeners ourselves...
- this.defaultValue = defaultValue;
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildDateChangeListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildDateChangeListener_());
- }
-
- protected PropertyChangeListener buildDateChangeListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- DateSpinnerModelAdapter.this.synchronize(event.getNewValue());
- }
- @Override
- public String toString() {
- return "date listener";
- }
- };
- }
-
-
- // ********** SpinnerModel implementation **********
-
- /**
- * Extend to check whether this method is being called before we
- * have any listeners.
- * This is necessary because some crappy jdk code gets the value
- * from the model *before* listening to the model. ~bjv
- * @see javax.swing.JSpinner.DefaultEditor(javax.swing.JSpinner)
- */
- @Override
- public Object getValue() {
- if (this.getChangeListeners().length == 0) {
- // sorry about this "lateral" call to super ~bjv
- super.setValue(this.spinnerValueOf(this.dateHolder.getValue()));
- }
- return super.getValue();
- }
-
- /**
- * Extend to update the underlying date directly.
- * The resulting event will be ignored: @see #synchronize(Object).
- */
- @Override
- public void setValue(Object value) {
- super.setValue(value);
- this.dateHolder.setValue(value);
- }
-
- /**
- * Extend to start listening to the underlying date if necessary.
- */
- @Override
- public void addChangeListener(ChangeListener listener) {
- if (this.getChangeListeners().length == 0) {
- this.dateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener);
- this.synchronize(this.dateHolder.getValue());
- }
- super.addChangeListener(listener);
- }
-
- /**
- * Extend to stop listening to the underlying date if appropriate.
- */
- @Override
- public void removeChangeListener(ChangeListener listener) {
- super.removeChangeListener(listener);
- if (this.getChangeListeners().length == 0) {
- this.dateHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener);
- }
- }
-
-
- // ********** queries **********
-
- protected Date getDefaultValue() {
- return this.defaultValue;
- }
-
- /**
- * Convert to a non-null value.
- */
- protected Object spinnerValueOf(Object value) {
- return (value == null) ? this.getDefaultValue() : value;
- }
-
-
- // ********** behavior **********
-
- /**
- * Set the spinner value if it has changed.
- */
- void synchronize(Object value) {
- Object newValue = this.spinnerValueOf(value);
- // check to see whether the spinner date has already been synchronized
- // (via #setValue())
- if ( ! this.getValue().equals(newValue)) {
- this.setValue(newValue);
- }
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.dateHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java
deleted file mode 100644
index eeb65b4965..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/DocumentAdapter.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.io.Serializable;
-import java.util.EventObject;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.EventListenerList;
-import javax.swing.event.UndoableEditEvent;
-import javax.swing.event.UndoableEditListener;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.Element;
-import javax.swing.text.PlainDocument;
-import javax.swing.text.Position;
-import javax.swing.text.Segment;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.text.Document can be used to keep a DocumentListener
- * (e.g. a JTextField) in synch with a PropertyValueModel that holds a string.
- *
- * NB: This model should only be used for "small" documents;
- * i.e. documents used by text fields, not text panes.
- * @see #synchronizeDelegate(String)
- */
-public class DocumentAdapter
- implements Document, Serializable
-{
-
- /** The delegate document whose behavior we "enhance". */
- protected final Document delegate;
-
- /** A listener that allows us to forward any changes made to the delegate document. */
- protected final CombinedListener delegateListener;
-
- /** A value model on the underlying model string. */
- protected final WritablePropertyValueModel<String> stringHolder;
-
- /** A listener that allows us to synchronize with changes made to the underlying model string. */
- protected final PropertyChangeListener stringListener;
-
- /** The event listener list for the document. */
- protected final EventListenerList listenerList = new EventListenerList();
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the string holder is required.
- * Wrap the specified document.
- */
- public DocumentAdapter(WritablePropertyValueModel<String> stringHolder, Document delegate) {
- super();
- if (stringHolder == null || delegate == null) {
- throw new NullPointerException();
- }
- this.stringHolder = stringHolder;
- // postpone listening to the underlying model string
- // until we have listeners ourselves...
- this.delegate = delegate;
- this.stringListener = this.buildStringListener();
- this.delegateListener = this.buildDelegateListener();
- }
-
- /**
- * Constructor - the string holder is required.
- * Wrap a plain document.
- */
- public DocumentAdapter(WritablePropertyValueModel<String> stringHolder) {
- this(stringHolder, new PlainDocument());
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildStringListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildStringListener_());
- }
-
- protected PropertyChangeListener buildStringListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- DocumentAdapter.this.stringChanged(event);
- }
- @Override
- public String toString() {
- return "string listener";
- }
- };
- }
-
- protected CombinedListener buildDelegateListener() {
- return new InternalListener();
- }
-
-
- // ********** Document implementation **********
-
- public int getLength() {
- return this.delegate.getLength();
- }
-
- /**
- * Extend to start listening to the underlying models if necessary.
- */
- public void addDocumentListener(DocumentListener listener) {
- if (this.listenerList.getListenerCount(DocumentListener.class) == 0) {
- this.delegate.addDocumentListener(this.delegateListener);
- this.engageStringHolder();
- }
- this.listenerList.add(DocumentListener.class, listener);
- }
-
- /**
- * Extend to stop listening to the underlying models if appropriate.
- */
- public void removeDocumentListener(DocumentListener listener) {
- this.listenerList.remove(DocumentListener.class, listener);
- if (this.listenerList.getListenerCount(DocumentListener.class) == 0) {
- this.disengageStringHolder();
- this.delegate.removeDocumentListener(this.delegateListener);
- }
- }
-
- /**
- * Extend to start listening to the delegate document if necessary.
- */
- public void addUndoableEditListener(UndoableEditListener listener) {
- if (this.listenerList.getListenerCount(UndoableEditListener.class) == 0) {
- this.delegate.addUndoableEditListener(this.delegateListener);
- }
- this.listenerList.add(UndoableEditListener.class, listener);
- }
-
- /**
- * Extend to stop listening to the delegate document if appropriate.
- */
- public void removeUndoableEditListener(UndoableEditListener listener) {
- this.listenerList.remove(UndoableEditListener.class, listener);
- if (this.listenerList.getListenerCount(UndoableEditListener.class) == 0) {
- this.delegate.removeUndoableEditListener(this.delegateListener);
- }
- }
-
- public Object getProperty(Object key) {
- return this.delegate.getProperty(key);
- }
-
- public void putProperty(Object key, Object value) {
- this.delegate.putProperty(key, value);
- }
-
- /**
- * Extend to update the underlying model string directly.
- * The resulting event will be ignored: @see #synchronizeDelegate(String).
- */
- public void remove(int offset, int len) throws BadLocationException {
- this.delegate.remove(offset, len);
- this.stringHolder.setValue(this.delegate.getText(0, this.delegate.getLength()));
- }
-
- /**
- * Extend to update the underlying model string directly.
- * The resulting event will be ignored: @see #synchronizeDelegate(String).
- */
- public void insertString(int offset, String insertedString, AttributeSet a) throws BadLocationException {
- this.delegate.insertString(offset, insertedString, a);
- this.stringHolder.setValue(this.delegate.getText(0, this.delegate.getLength()));
- }
-
- public String getText(int offset, int length) throws BadLocationException {
- return this.delegate.getText(offset, length);
- }
-
- public void getText(int offset, int length, Segment txt) throws BadLocationException {
- this.delegate.getText(offset, length, txt);
- }
-
- public Position getStartPosition() {
- return this.delegate.getStartPosition();
- }
-
- public Position getEndPosition() {
- return this.delegate.getEndPosition();
- }
-
- public Position createPosition(int offs) throws BadLocationException {
- return this.delegate.createPosition(offs);
- }
-
- public Element[] getRootElements() {
- return this.delegate.getRootElements();
- }
-
- public Element getDefaultRootElement() {
- return this.delegate.getDefaultRootElement();
- }
-
- public void render(Runnable r) {
- this.delegate.render(r);
- }
-
-
- // ********** queries **********
-
- public DocumentListener[] documentListeners() {
- return this.listenerList.getListeners(DocumentListener.class);
- }
-
- public UndoableEditListener[] undoableEditListeners() {
- return this.listenerList.getListeners(UndoableEditListener.class);
- }
-
-
- // ********** behavior **********
-
- /**
- * A third party has modified the underlying model string.
- * Synchronize the delegate document accordingly.
- */
- protected void stringChanged(PropertyChangeEvent event) {
- this.synchronizeDelegate((String) event.getNewValue());
- }
-
- /**
- * Replace the document's entire text string with the new string.
- */
- protected void synchronizeDelegate(String s) {
- try {
- int len = this.delegate.getLength();
- // check to see whether the delegate has already been synchronized
- // (via #insertString() or #remove())
- if ( ! this.delegate.getText(0, len).equals(s)) {
- this.delegate.remove(0, len);
- this.delegate.insertString(0, s, null);
- }
- } catch (BadLocationException ex) {
- throw new IllegalStateException(ex.getMessage()); // this should not happen...
- }
- }
-
- protected void engageStringHolder() {
- this.stringHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
- this.synchronizeDelegate(this.stringHolder.getValue());
- }
-
- protected void disengageStringHolder() {
- this.stringHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
- }
-
- protected void delegateChangedUpdate(DocumentEvent event) {
- // no need to lazy-initialize the event;
- // we wouldn't get here if we did not have listeners...
- DocumentEvent ee = new InternalDocumentEvent(this, event);
- DocumentListener[] listeners = this.documentListeners();
- for (int i = listeners.length; i-- > 0; ) {
- listeners[i].changedUpdate(ee);
- }
- }
-
- protected void delegateInsertUpdate(DocumentEvent event) {
- // no need to lazy-initialize the event;
- // we wouldn't get here if we did not have listeners...
- DocumentEvent ee = new InternalDocumentEvent(this, event);
- DocumentListener[] listeners = this.documentListeners();
- for (int i = listeners.length; i-- > 0; ) {
- listeners[i].insertUpdate(ee);
- }
- }
-
- protected void delegateRemoveUpdate(DocumentEvent event) {
- // no need to lazy-initialize the event;
- // we wouldn't get here if we did not have listeners...
- DocumentEvent ee = new InternalDocumentEvent(this, event);
- DocumentListener[] listeners = this.documentListeners();
- for (int i = listeners.length; i-- > 0; ) {
- listeners[i].removeUpdate(ee);
- }
- }
-
- protected void delegateUndoableEditHappened(UndoableEditEvent event) {
- // no need to lazy-initialize the event;
- // we wouldn't get here if we did not have listeners...
- UndoableEditEvent ee = new UndoableEditEvent(this, event.getEdit());
- UndoableEditListener[] listeners = this.undoableEditListeners();
- for (int i = listeners.length; i-- > 0; ) {
- listeners[i].undoableEditHappened(ee);
- }
- }
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.stringHolder);
- }
-
-
-// ********** inner class **********
-
- protected interface CombinedListener extends DocumentListener, UndoableEditListener {
- // just consolidate the two interfaces
- }
-
- protected class InternalListener implements CombinedListener {
- public void changedUpdate(DocumentEvent event) {
- DocumentAdapter.this.delegateChangedUpdate(event);
- }
- public void insertUpdate(DocumentEvent event) {
- DocumentAdapter.this.delegateInsertUpdate(event);
- }
- public void removeUpdate(DocumentEvent event) {
- DocumentAdapter.this.delegateRemoveUpdate(event);
- }
- public void undoableEditHappened(UndoableEditEvent event) {
- DocumentAdapter.this.delegateUndoableEditHappened(event);
- }
- }
-
- protected static class InternalDocumentEvent
- extends EventObject
- implements DocumentEvent
- {
- protected DocumentEvent delegate;
-
- protected InternalDocumentEvent(Document document, DocumentEvent delegate) {
- super(document);
- this.delegate = delegate;
- }
- public ElementChange getChange(Element elem) {
- return this.delegate.getChange(elem);
- }
- public Document getDocument() {
- return (Document) this.source;
- }
- public int getLength() {
- return this.delegate.getLength();
- }
- public int getOffset() {
- return this.delegate.getOffset();
- }
- public EventType getType() {
- return this.delegate.getType();
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java
deleted file mode 100644
index 42e952f6b0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListModelAdapter.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import javax.swing.AbstractListModel;
-import javax.swing.event.ListDataListener;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTListChangeListenerWrapper;
-import org.eclipse.jpt.utility.internal.model.value.CollectionListValueModelAdapter;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * This javax.swing.ListModel can be used to keep a ListDataListener
- * (e.g. a JList) in synch with a ListValueModel (or a CollectionValueModel).
- *
- * An instance of this ListModel *must* be supplied with a value model,
- * which is a ListValueModel on the bound list or a CollectionValueModel
- * on the bound collection. This is required - the list (or collection)
- * itself can be null, but the value model that holds it cannot.
- */
-public class ListModelAdapter
- extends AbstractListModel
-{
- /** A value model on the underlying model list. */
- protected ListValueModel<?> listHolder;
-
- /**
- * Cache the size of the list for "dramatic" changes.
- * @see #listChanged(ListChangeEvent)
- */
- protected int listSize;
-
- /** A listener that allows us to forward changes made to the underlying model list. */
- protected final ListChangeListener listChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Default constructor - initialize stuff.
- */
- private ListModelAdapter() {
- super();
- this.listSize = 0;
- this.listChangeListener = this.buildListChangeListener();
- }
-
- /**
- * Constructor - the list holder is required.
- */
- public ListModelAdapter(ListValueModel<?> listHolder) {
- this();
- this.setModel(listHolder);
- }
-
- /**
- * Constructor - the collection holder is required.
- */
- public ListModelAdapter(CollectionValueModel<?> collectionHolder) {
- this();
- this.setModel(collectionHolder);
- }
-
-
- // ********** initialization **********
-
- protected ListChangeListener buildListChangeListener() {
- return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
- }
-
- protected ListChangeListener buildListChangeListener_() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- ListModelAdapter.this.itemsAdded(event);
- }
- public void itemsRemoved(ListChangeEvent event) {
- ListModelAdapter.this.itemsRemoved(event);
- }
- public void itemsReplaced(ListChangeEvent event) {
- ListModelAdapter.this.itemsReplaced(event);
- }
- public void itemsMoved(ListChangeEvent event) {
- ListModelAdapter.this.itemsMoved(event);
- }
- public void listCleared(ListChangeEvent event) {
- ListModelAdapter.this.listCleared();
- }
- public void listChanged(ListChangeEvent event) {
- ListModelAdapter.this.listChanged();
- }
- @Override
- public String toString() {
- return "list listener";
- }
- };
- }
-
-
- // ********** ListModel implementation **********
-
- public int getSize() {
- return this.listHolder.size();
- }
-
- public Object getElementAt(int index) {
- return this.listHolder.get(index);
- }
-
- /**
- * Extend to start listening to the underlying model list if necessary.
- */
- @Override
- public void addListDataListener(ListDataListener l) {
- if (this.hasNoListDataListeners()) {
- this.engageModel();
- this.listSize = this.listHolder.size();
- }
- super.addListDataListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model list if appropriate.
- */
- @Override
- public void removeListDataListener(ListDataListener l) {
- super.removeListDataListener(l);
- if (this.hasNoListDataListeners()) {
- this.disengageModel();
- this.listSize = 0;
- }
- }
-
-
- // ********** public API **********
-
- /**
- * Return the underlying list model.
- */
- public ListValueModel<?> model() {
- return this.listHolder;
- }
-
- /**
- * Set the underlying list model.
- */
- public void setModel(ListValueModel<?> listHolder) {
- if (listHolder == null) {
- throw new NullPointerException();
- }
- boolean hasListeners = this.hasListDataListeners();
- if (hasListeners) {
- this.disengageModel();
- }
- this.listHolder = listHolder;
- if (hasListeners) {
- this.engageModel();
- this.listChanged();
- }
- }
-
- /**
- * Set the underlying collection model.
- */
- @SuppressWarnings("unchecked")
- public void setModel(CollectionValueModel<?> collectionHolder) {
- this.setModel(new CollectionListValueModelAdapter(collectionHolder));
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether this model has no listeners.
- */
- protected boolean hasNoListDataListeners() {
- return this.getListDataListeners().length == 0;
- }
-
- /**
- * Return whether this model has any listeners.
- */
- protected boolean hasListDataListeners() {
- return ! this.hasNoListDataListeners();
- }
-
-
- // ********** behavior **********
-
- protected void engageModel() {
- this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
- protected void disengageModel() {
- this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
-
-
- // ********** list change support **********
-
- /**
- * Items were added to the underlying model list.
- * Notify listeners of the changes.
- */
- protected void itemsAdded(ListChangeEvent event) {
- int start = event.getIndex();
- int end = start + event.itemsSize() - 1;
- this.fireIntervalAdded(this, start, end);
- this.listSize += event.itemsSize();
- }
-
- /**
- * Items were removed from the underlying model list.
- * Notify listeners of the changes.
- */
- protected void itemsRemoved(ListChangeEvent event) {
- int start = event.getIndex();
- int end = start + event.itemsSize() - 1;
- this.fireIntervalRemoved(this, start, end);
- this.listSize -= event.itemsSize();
- }
-
- /**
- * Items were replaced in the underlying model list.
- * Notify listeners of the changes.
- */
- protected void itemsReplaced(ListChangeEvent event) {
- int start = event.getIndex();
- int end = start + event.itemsSize() - 1;
- this.fireContentsChanged(this, start, end);
- }
-
- /**
- * Items were moved in the underlying model list.
- * Notify listeners of the changes.
- */
- protected void itemsMoved(ListChangeEvent event) {
- int start = Math.min(event.getSourceIndex(), event.getTargetIndex());
- int end = Math.max(event.getSourceIndex(), event.getTargetIndex()) + event.getMoveLength() - 1;
- this.fireContentsChanged(this, start, end);
- }
-
- /**
- * The underlying model list was cleared.
- * Notify listeners of the changes.
- */
- protected void listCleared() {
- if (this.listSize != 0) {
- this.fireIntervalRemoved(this, 0, this.listSize - 1);
- this.listSize = 0;
- }
- }
-
- /**
- * The underlying model list has changed "dramatically".
- * Notify listeners of the changes.
- */
- protected void listChanged() {
- if (this.listSize != 0) {
- this.fireIntervalRemoved(this, 0, this.listSize - 1);
- }
- this.listSize = this.listHolder.size();
- if (this.listSize != 0) {
- this.fireIntervalAdded(this, 0, this.listSize - 1);
- }
- }
-
-
- // ********** Object overrides **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.listHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java
deleted file mode 100644
index 527120367b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ListSpinnerModelAdapter.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.util.Arrays;
-import java.util.List;
-import javax.swing.SpinnerListModel;
-import javax.swing.event.ChangeListener;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.SpinnerListModel can be used to keep a ChangeListener
- * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a value
- * in the list.
- *
- * This class must be a sub-class of SpinnerListModel because of some
- * crappy jdk code.... ~bjv
- * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
- *
- * NB: This model should only be used for values that have a reasonably
- * inexpensive #equals() implementation.
- * @see #synchronize(Object)
- *
- * If this class needs to be modified, it would behoove us to review the
- * other, similar classes:
- * @see DateSpinnerModelAdapter
- * @see NumberSpinnerModelAdapter
- */
-public class ListSpinnerModelAdapter
- extends SpinnerListModel
-{
-
- /**
- * The default spinner value; used when the underlying model value is null.
- * The default is the first item on the list.
- */
- private final Object defaultValue;
-
- /** A value model on the underlying value. */
- private final WritablePropertyValueModel<Object> valueHolder;
-
- /** A listener that allows us to synchronize with changes made to the underlying value. */
- private final PropertyChangeListener valueChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the value holder is required.
- * Use the model value itself as the default spinner value.
- */
- public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder) {
- this(valueHolder, valueHolder.getValue());
- }
-
- /**
- * Constructor - the value holder is required.
- */
- public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object defaultValue) {
- this(valueHolder, new Object[] {defaultValue}, defaultValue);
- }
-
- /**
- * Constructor - the value holder is required.
- * Use the first item in the list of values as the default spinner value.
- */
- public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object[] values) {
- this(valueHolder, values, values[0]);
- }
-
- /**
- * Constructor - the value holder is required.
- */
- public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object[] values, Object defaultValue) {
- this(valueHolder, Arrays.asList(values), defaultValue);
- }
-
- /**
- * Constructor - the value holder is required.
- * Use the first item in the list of values as the default spinner value.
- */
- public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, List<Object> values) {
- this(valueHolder, values, values.get(0));
- }
-
- /**
- * Constructor - the value holder is required.
- */
- public ListSpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, List<Object> values, Object defaultValue) {
- super(values);
- this.valueHolder = valueHolder;
- this.valueChangeListener = this.buildValueChangeListener();
- // postpone listening to the underlying value
- // until we have listeners ourselves...
- this.defaultValue = defaultValue;
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildValueChangeListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildValueChangeListener_());
- }
-
- protected PropertyChangeListener buildValueChangeListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- ListSpinnerModelAdapter.this.synchronize(event.getNewValue());
- }
- @Override
- public String toString() {
- return "value listener";
- }
- };
- }
-
-
- // ********** SpinnerModel implementation **********
-
- /**
- * Extend to check whether this method is being called before we
- * have any listeners.
- * This is necessary because some crappy jdk code gets the value
- * from the model *before* listening to the model. ~bjv
- * @see javax.swing.JSpinner.DefaultEditor(javax.swing.JSpinner)
- */
- @Override
- public Object getValue() {
- if (this.getChangeListeners().length == 0) {
- // sorry about this "lateral" call to super ~bjv
- super.setValue(this.spinnerValueOf(this.valueHolder.getValue()));
- }
- return super.getValue();
- }
-
- /**
- * Extend to update the underlying value directly.
- * The resulting event will be ignored: @see #synchronize(Object).
- */
- @Override
- public void setValue(Object value) {
- super.setValue(value);
- this.valueHolder.setValue(value);
- }
-
- /**
- * Extend to start listening to the underlying value if necessary.
- */
- @Override
- public void addChangeListener(ChangeListener listener) {
- if (this.getChangeListeners().length == 0) {
- this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
- this.synchronize(this.valueHolder.getValue());
- }
- super.addChangeListener(listener);
- }
-
- /**
- * Extend to stop listening to the underlying value if appropriate.
- */
- @Override
- public void removeChangeListener(ChangeListener listener) {
- super.removeChangeListener(listener);
- if (this.getChangeListeners().length == 0) {
- this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
- }
- }
-
-
- // ********** queries **********
-
- protected Object getDefaultValue() {
- return this.defaultValue;
- }
-
- /**
- * Convert to a non-null value.
- */
- protected Object spinnerValueOf(Object value) {
- return (value == null) ? this.getDefaultValue() : value;
- }
-
-
- // ********** behavior **********
-
- /**
- * Set the spinner value if it has changed.
- */
- void synchronize(Object value) {
- Object newValue = this.spinnerValueOf(value);
- // check to see whether the spinner value has already been synchronized
- // (via #setValue())
- if ( ! this.getValue().equals(newValue)) {
- this.setValue(newValue);
- }
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.valueHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java
deleted file mode 100644
index 484ff33c3a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/NumberSpinnerModelAdapter.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import javax.swing.SpinnerNumberModel;
-import javax.swing.event.ChangeListener;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.SpinnerNumberModel can be used to keep a ChangeListener
- * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a number.
- *
- * This class must be a sub-class of SpinnerNumberModel because of some
- * crappy jdk code.... ~bjv
- * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
- *
- * If this class needs to be modified, it would behoove us to review the
- * other, similar classes:
- * @see DateSpinnerModelAdapter
- * @see ListSpinnerModelAdapter
- */
-public class NumberSpinnerModelAdapter
- extends SpinnerNumberModel
-{
-
- /**
- * The default spinner value; used when the
- * underlying model number value is null.
- */
- private final Number defaultValue;
-
- /** A value model on the underlying number. */
- private final WritablePropertyValueModel<Number> numberHolder;
-
- /**
- * A listener that allows us to synchronize with
- * changes made to the underlying number.
- */
- private final PropertyChangeListener numberChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the number holder is required.
- * The default spinner value is zero.
- * The step size is one.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder) {
- this(numberHolder, 0);
- }
-
- /**
- * Constructor - the number holder is required.
- * The step size is one.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, int defaultValue) {
- this(numberHolder, null, null, new Integer(1), new Integer(defaultValue));
- }
-
- /**
- * Constructor - the number holder is required.
- * Use the minimum value as the default spinner value.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize) {
- this(numberHolder, minimum, maximum, stepSize, minimum);
- }
-
- /**
- * Constructor - the number holder is required.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize, int defaultValue) {
- this(numberHolder, new Integer(minimum), new Integer(maximum), new Integer(stepSize), new Integer(defaultValue));
- }
-
- /**
- * Constructor - the number holder is required.
- * Use the minimum value as the default spinner value.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, double value, double minimum, double maximum, double stepSize) {
- this(numberHolder, value, minimum, maximum, stepSize, minimum);
- }
-
- /**
- * Constructor - the number holder is required.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, double value, double minimum, double maximum, double stepSize, double defaultValue) {
- this(numberHolder, new Double(minimum), new Double(maximum), new Double(stepSize), new Double(defaultValue));
- }
-
- /**
- * Constructor - the number holder is required.
- */
- public NumberSpinnerModelAdapter(WritablePropertyValueModel<Number> numberHolder, Comparable<?> minimum, Comparable<?> maximum, Number stepSize, Number defaultValue) {
- super(numberHolder.getValue() == null ? defaultValue : (Number) numberHolder.getValue(), minimum, maximum, stepSize);
- this.numberHolder = numberHolder;
- this.numberChangeListener = this.buildNumberChangeListener();
- // postpone listening to the underlying number
- // until we have listeners ourselves...
- this.defaultValue = defaultValue;
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildNumberChangeListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildNumberChangeListener_());
- }
-
- protected PropertyChangeListener buildNumberChangeListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- NumberSpinnerModelAdapter.this.synchronize(event.getNewValue());
- }
- @Override
- public String toString() {
- return "number listener";
- }
- };
- }
-
-
- // ********** SpinnerModel implementation **********
-
- /**
- * Extend to check whether this method is being called before we
- * have any listeners.
- * This is necessary because some crappy jdk code gets the value
- * from the model *before* listening to the model. ~bjv
- * @see javax.swing.JSpinner.DefaultEditor(javax.swing.JSpinner)
- */
- @Override
- public Object getValue() {
- if (this.getChangeListeners().length == 0) {
- // sorry about this "lateral" call to super ~bjv
- super.setValue(this.spinnerValueOf(this.numberHolder.getValue()));
- }
- return super.getValue();
- }
-
- /**
- * Extend to update the underlying number directly.
- * The resulting event will be ignored: @see #synchronizeDelegate(Object).
- */
- @Override
- public void setValue(Object value) {
- super.setValue(value);
- this.numberHolder.setValue((Number) value);
- }
-
- /**
- * Extend to start listening to the underlying number if necessary.
- */
- @Override
- public void addChangeListener(ChangeListener listener) {
- if (this.getChangeListeners().length == 0) {
- this.numberHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener);
- this.synchronize(this.numberHolder.getValue());
- }
- super.addChangeListener(listener);
- }
-
- /**
- * Extend to stop listening to the underlying number if appropriate.
- */
- @Override
- public void removeChangeListener(ChangeListener listener) {
- super.removeChangeListener(listener);
- if (this.getChangeListeners().length == 0) {
- this.numberHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener);
- }
- }
-
-
- // ********** queries **********
-
- protected Number getDefaultValue() {
- return this.defaultValue;
- }
-
- /**
- * Convert to a non-null value.
- */
- protected Object spinnerValueOf(Object value) {
- return (value == null) ? this.getDefaultValue() : value;
- }
-
-
- // ********** behavior **********
-
- /**
- * Set the spinner value if it has changed.
- */
- void synchronize(Object value) {
- Object newValue = this.spinnerValueOf(value);
- // check to see whether the date has already been synchronized
- // (via #setValue())
- if ( ! this.getValue().equals(newValue)) {
- this.setValue(newValue);
- }
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.numberHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java
deleted file mode 100644
index 61d2e3701f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ObjectListSelectionModel.java
+++ /dev/null
@@ -1,427 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import javax.swing.DefaultListSelectionModel;
-import javax.swing.ListModel;
-import javax.swing.event.ListDataEvent;
-import javax.swing.event.ListDataListener;
-import javax.swing.event.ListSelectionListener;
-import org.eclipse.jpt.utility.internal.CollectionTools;
-
-/**
- * This ListSelectionModel is aware of the ListModel and
- * provides convenience methods to access and set the
- * selected *objects*, as opposed to the selected *indexes*.
- */
-public class ObjectListSelectionModel
- extends DefaultListSelectionModel
-{
- /** The list model referenced by the list selection model. */
- private final ListModel listModel;
-
- /** A listener that allows us to clear the selection when the list model has changed. */
- private final ListDataListener listDataListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a list selection model for the specified list model.
- */
- public ObjectListSelectionModel(ListModel listModel) {
- super();
- this.listModel = listModel;
- this.listDataListener = this.buildListDataListener();
- }
-
-
- // ********** initialization **********
-
- private ListDataListener buildListDataListener() {
- return new ListDataListener() {
- public void intervalAdded(ListDataEvent event) {
- // this does not affect the selection
- }
- public void intervalRemoved(ListDataEvent event) {
- // this does not affect the selection
- }
- public void contentsChanged(ListDataEvent event) {
- ObjectListSelectionModel.this.listModelContentsChanged(event);
- }
- @Override
- public String toString() {
- return "list data listener";
- }
- };
- }
-
- /**
- * Typically, the selection does not need to be cleared when the
- * contents of the list have changed. Most of the time this just
- * means an item has changed in a way that affects its display string
- * or icon. We typically only use the class for edits involving
- * single selection.
- * A subclass can override this method if the selection
- * should be cleared because a change could mean the selection is invalid.
- */
- protected void listModelContentsChanged(ListDataEvent event) {
- /**this.clearSelection();*/
- }
-
-
- // ********** ListSelectionModel implementation **********
-
- @Override
- public void addListSelectionListener(ListSelectionListener l) {
- if (this.hasNoListSelectionListeners()) {
- this.listModel.addListDataListener(this.listDataListener);
- }
- super.addListSelectionListener(l);
- }
-
- @Override
- public void removeListSelectionListener(ListSelectionListener l) {
- super.removeListSelectionListener(l);
- if (this.hasNoListSelectionListeners()) {
- this.listModel.removeListDataListener(this.listDataListener);
- }
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether this model has no listeners.
- */
- protected boolean hasNoListSelectionListeners() { // private-protected
- return this.getListSelectionListeners().length == 0;
- }
-
- /**
- * Return the list model referenced by the list selection model.
- */
- public ListModel getListModel() {
- return this.listModel;
- }
-
- public int selectedValuesSize() {
- int min = this.getMinSelectionIndex();
- int max = this.getMaxSelectionIndex();
-
- if ((min < 0) || (max < 0)) {
- return 0;
- }
-
- int n = 0;
- int count = this.getListModel().getSize();
- for (int i = min; i <= max; i++) {
- if (this.isSelectedIndex(i) && (i < count)) {
- n++;
- }
- }
- return n;
- }
-
- /**
- * Return the first selected value.
- * Return null if the selection is empty.
- */
- public Object selectedValue() {
- int index = this.getMinSelectionIndex();
- if (index == -1) {
- return null;
- }
- if (this.getListModel().getSize() <= index) {
- return null;
- }
- return this.getListModel().getElementAt(index);
- }
-
- /**
- * Return an array of the selected values.
- */
- public Object[] selectedValues() {
- int min = this.getMinSelectionIndex();
- int max = this.getMaxSelectionIndex();
-
- if ((min < 0) || (max < 0)) {
- return new Object[0];
- }
-
- int maxSize = (max - min) + 1;
- Object[] temp = new Object[maxSize];
- int n = 0;
- int count = this.getListModel().getSize();
- for (int i = min; i <= max; i++) {
- if (this.isSelectedIndex(i) && (i < count)) {
- temp[n++] = this.getListModel().getElementAt(i);
- }
- }
- if (n == maxSize) {
- // all the elements in the range were selected
- return temp;
- }
- // only some of the elements in the range were selected
- Object[] result = new Object[n];
- System.arraycopy(temp, 0, result, 0, n);
- return result;
- }
-
- /**
- * Return an array of the selected indices in order.
- */
- public int[] selectedIndices() {
- int min = this.getMinSelectionIndex();
- int max = this.getMaxSelectionIndex();
-
- if ((min < 0) || (max < 0)) {
- return new int[0];
- }
-
- int maxSize = (max - min) + 1;
- int[] temp = new int[maxSize];
- int n = 0;
- int count = this.getListModel().getSize();
- for (int i = min; i <= max; i++) {
- if (this.isSelectedIndex(i) && (i < count)) {
- temp[n++] = i;
- }
- }
- if (n == maxSize) {
- // all the elements in the range were selected
- Arrays.sort(temp);
- return temp;
- }
- // only some of the elements in the range were selected
- int[] result = new int[n];
- System.arraycopy(temp, 0, result, 0, n);
- Arrays.sort(result);
- return result;
- }
-
- /**
- * Set the selected value.
- */
- public void setSelectedValue(Object object) {
- this.setSelectedValues(CollectionTools.singletonIterator(object));
- }
-
- /**
- * Set the current set of selected objects to the specified objects.
- * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
- */
- public void setSelectedValues(Iterator<?> objects) {
- this.setValueIsAdjusting(true);
- this.clearSelection();
- this.addSelectedValuesInternal(objects);
- this.setValueIsAdjusting(false);
- }
-
- /**
- * Set the current set of selected objects to the specified objects.
- * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
- */
- public void setSelectedValues(Collection<?> objects) {
- this.setSelectedValues(objects.iterator());
- }
-
- /**
- * Set the current set of selected objects to the specified objects.
- * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
- */
- public void setSelectedValues(Object[] objects) {
- this.setSelectedValues(CollectionTools.iterator(objects));
- }
-
- /**
- * Add the specified object to the current set of selected objects.
- * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
- */
- public void addSelectedValue(Object object) {
- this.addSelectedValues(CollectionTools.singletonIterator(object));
- }
-
- /**
- * Add the specified objects to the current set of selected objects.
- * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
- */
- public void addSelectedValues(Iterator<?> objects) {
- this.setValueIsAdjusting(true);
- this.addSelectedValuesInternal(objects);
- this.setValueIsAdjusting(false);
- }
-
- /**
- * Add the specified objects to the current set of selected objects.
- * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
- */
- public void addSelectedValues(Collection<?> objects) {
- this.addSelectedValues(objects.iterator());
- }
-
- /**
- * Add the specified objects to the current set of selected objects.
- * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
- */
- public void addSelectedValues(Object[] objects) {
- this.addSelectedValues(CollectionTools.iterator(objects));
- }
-
- /**
- * Remove the specified object from the current set of selected objects.
- * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
- */
- public void removeSelectedValue(Object object) {
- this.removeSelectedValues(CollectionTools.singletonIterator(object));
- }
-
- /**
- * Remove the specified objects from the current set of selected objects.
- * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
- */
- public void removeSelectedValues(Iterator<?> objects) {
- this.setValueIsAdjusting(true);
- ListModel lm = this.getListModel();
- int lmSize = lm.getSize();
- while (objects.hasNext()) {
- int index = this.indexOf(objects.next(), lm, lmSize);
- this.removeSelectionInterval(index, index);
- }
- this.setValueIsAdjusting(false);
- }
-
- /**
- * Remove the specified objects from the current set of selected objects.
- * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
- */
- public void removeSelectedValues(Collection<?> objects) {
- this.removeSelectedValues(objects.iterator());
- }
-
- /**
- * Remove the specified objects from the current set of selected objects.
- * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
- */
- public void removeSelectedValues(Object[] objects) {
- this.removeSelectedValues(CollectionTools.iterator(objects));
- }
-
- /**
- * @see javax.swing.ListSelectionModel#getAnchorSelectionIndex()
- * Return null if the anchor selection is empty.
- */
- public Object getAnchorSelectedValue() {
- int index = this.getAnchorSelectionIndex();
- if (index == -1) {
- return null;
- }
- return this.getListModel().getElementAt(index);
- }
-
- /**
- * @see javax.swing.ListSelectionModel#setAnchorSelectionIndex(int)
- */
- public void setAnchorSelectedValue(Object object) {
- this.setAnchorSelectionIndex(this.indexOf(object));
- }
-
- /**
- * @see javax.swing.ListSelectionModel#getLeadSelectionIndex()
- * Return null if the lead selection is empty.
- */
- public Object getLeadSelectedValue() {
- int index = this.getLeadSelectionIndex();
- if (index == -1) {
- return null;
- }
- return this.getListModel().getElementAt(index);
- }
-
- /**
- * @see javax.swing.ListSelectionModel#setLeadSelectionIndex(int)
- */
- public void setLeadSelectedValue(Object object) {
- this.setLeadSelectionIndex(this.indexOf(object));
- }
-
- /**
- * @see javax.swing.ListSelectionModel#getMaxSelectionIndex()
- * Return null if the max selection is empty.
- */
- public Object getMaxSelectedValue() {
- int index = this.getMaxSelectionIndex();
- if (index == -1) {
- return null;
- }
- return this.getListModel().getElementAt(index);
- }
-
- /**
- * @see javax.swing.ListSelectionModel#getMinSelectionIndex()
- * Return null if the min selection is empty.
- */
- public Object getMinSelectedValue() {
- int index = this.getMinSelectionIndex();
- if (index == -1) {
- return null;
- }
- return this.getListModel().getElementAt(index);
- }
-
- /**
- * @see javax.swing.ListSelectionModel#isSelectedIndex(int)
- */
- public boolean valueIsSelected(Object object) {
- return this.isSelectedIndex(this.indexOf(object));
- }
-
- /**
- * Add the specified objects to the current set of selected objects,
- * without wrapping the actions in "adjusting" events.
- */
- private void addSelectedValuesInternal(Iterator<?> objects) {
- ListModel lm = this.getListModel();
- int listModelSize = lm.getSize();
- while (objects.hasNext()) {
- int index = this.indexOf(objects.next(), lm, listModelSize);
- this.addSelectionInterval(index, index);
- }
- }
-
- /**
- * Return the index in the list model of the specified object.
- * Return -1 if the object is not in the list model.
- */
- private int indexOf(Object object) {
- ListModel lm = this.getListModel();
- return this.indexOf(object, lm, lm.getSize());
- }
-
- /**
- * Return the index in the list model of the specified object.
- * Return -1 if the object is not in the list model.
- */
- // we're just jerking around with performance optimizations here
- // (in memory of Phil...);
- // call this method inside loops that do not modify the listModel
- private int indexOf(Object object, ListModel lm, int listModelSize) {
- for (int i = listModelSize; i-- > 0; ) {
- if (lm.getElementAt(i) == object) {
- return i;
- }
- }
- return -1;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java
deleted file mode 100644
index 2bc8a17734..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/PrimitiveListTreeModel.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.ListIterator;
-import javax.swing.event.TreeModelListener;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.MutableTreeNode;
-import javax.swing.tree.TreeNode;
-import javax.swing.tree.TreePath;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTListChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-
-/**
- * This TreeModel implementation provides a tree with a "null" root that
- * has a set of "primitive" children. These "primitive" children do not have
- * children themselves, making the tree a maximum of 2 levels deep.
- * This model automatically synchronizes the root's children with a
- * ListValueModel that holds a collection of primitive (non-model) objects
- * (e.g. Strings).
- *
- * This is useful for providing an "editable" list of primitives. Since the JDK
- * does not provide us with an editable listbox, we must use an editable tree.
- * We wrap everything in DefaultMutableTreeNodes.
- *
- * Subclasses must implement #primitiveChanged(int, Object) and update
- * the model appropriately. This method is called when the user edits the
- * list directly and presses <Enter>.
- *
- * The JTree using this model must be configured as "editable":
- * tree.setEditable(true);
- */
-// TODO convert to use an adapter instead of requiring subclass
-public abstract class PrimitiveListTreeModel
- extends DefaultTreeModel
-{
- /** a model on the list of primitives */
- private final ListValueModel<?> listHolder;
-
- /** a listener that handles the adding, removing, and replacing of the primitives */
- private final ListChangeListener listChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Public constructor - the list holder is required
- */
- public PrimitiveListTreeModel(ListValueModel<?> listHolder) {
- super(new DefaultMutableTreeNode(null, true)); // true = the root can have children
- if (listHolder == null) {
- throw new NullPointerException();
- }
- this.listHolder = listHolder;
- this.listChangeListener = this.buildListChangeListener();
- // postpone listening to the model until we have listeners ourselves
- }
-
- protected ListChangeListener buildListChangeListener() {
- return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
- }
-
- protected ListChangeListener buildListChangeListener_() {
- return new PrimitiveListChangeListener();
- }
-
-
- // ********** behavior **********
-
- /**
- * Subclasses should override this method to update the
- * model appropriately. The primitive at the specified index was
- * edited directly by the user and the new value is as specified.
- * Convert the value appropriately and place it in the model.
- */
- protected abstract void primitiveChanged(int index, Object newValue);
-
-
- // ********** TreeModel implementation **********
-
- /**
- * Override to change the underlying model instead of changing the node directly.
- */
- @Override
- public void valueForPathChanged(TreePath path, Object newValue) {
- TreeNode node = (TreeNode) path.getLastPathComponent();
- int index = ((TreeNode) this.getRoot()).getIndex(node);
- this.primitiveChanged(index, newValue);
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public void addTreeModelListener(TreeModelListener l) {
- if (this.getTreeModelListeners().length == 0) {
- this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- this.synchronizeList();
- }
- super.addTreeModelListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model if appropriate.
- */
- @Override
- public void removeTreeModelListener(TreeModelListener l) {
- super.removeTreeModelListener(l);
- if (this.getTreeModelListeners().length == 0) {
- this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Synchronize our list of nodes with the list of primitives
- */
- void synchronizeList() {
- this.clearList();
- this.buildList();
- }
-
- void clearList() {
- int childcount = this.root.getChildCount();
- for (int i = childcount - 1; i >= 0; i--) {
- this.removeNodeFromParent((MutableTreeNode)this.root.getChildAt(i));
- }
- }
-
- private void buildList() {
- for (Iterator<?> stream = this.listHolder.iterator(); stream.hasNext(); ) {
- this.addPrimitive(stream.next());
- }
- }
-
- /**
- * Add the specified primitive to the end of the list.
- */
- private void addPrimitive(Object primitive) {
- this.insertPrimitive(this.root.getChildCount(), primitive);
- }
-
- /**
- * Create a node for the specified primitive
- * and insert it as a child of the root.
- */
- void insertPrimitive(int index, Object primitive) {
- DefaultMutableTreeNode node = new DefaultMutableTreeNode(primitive, false); // don't allow children on the child node
- this.insertNodeInto(node, (MutableTreeNode) this.root, index);
- }
-
- /**
- * Remove node at the specified index.
- */
- MutableTreeNode removeNode(int index) {
- MutableTreeNode node = (MutableTreeNode) this.root.getChildAt(index);
- this.removeNodeFromParent(node);
- return node;
- }
-
- /**
- * Replace the user object of the node at childIndex.
- */
- void replacePrimitive(int index, Object primitive) {
- MutableTreeNode node = (MutableTreeNode) this.root.getChildAt(index);
- node.setUserObject(primitive);
- this.nodeChanged(node);
- }
-
-
- // ********** inner class **********
-
- private class PrimitiveListChangeListener implements ListChangeListener {
- PrimitiveListChangeListener() {
- super();
- }
-
- public void itemsAdded(ListChangeEvent event) {
- int i = event.getIndex();
- for (ListIterator<?> stream = event.items(); stream.hasNext(); ) {
- PrimitiveListTreeModel.this.insertPrimitive(i++, stream.next());
- }
- }
-
- public void itemsRemoved(ListChangeEvent event) {
- for (int i = 0; i < event.itemsSize(); i++) {
- PrimitiveListTreeModel.this.removeNode(event.getIndex());
- }
- }
-
- public void itemsReplaced(ListChangeEvent event) {
- int i = event.getIndex();
- for (ListIterator<?> stream = event.items(); stream.hasNext(); ) {
- PrimitiveListTreeModel.this.replacePrimitive(i++, stream.next());
- }
- }
-
- public void itemsMoved(ListChangeEvent event) {
- ArrayList<MutableTreeNode> temp = new ArrayList<MutableTreeNode>(event.getMoveLength());
- for (int i = 0; i < event.getMoveLength(); i++) {
- temp.add(PrimitiveListTreeModel.this.removeNode(event.getSourceIndex()));
- }
- int i = event.getTargetIndex();
- for (MutableTreeNode node : temp) {
- PrimitiveListTreeModel.this.insertPrimitive(i++, node);
- }
- }
-
- public void listCleared(ListChangeEvent event) {
- PrimitiveListTreeModel.this.clearList();
- }
-
- public void listChanged(ListChangeEvent event) {
- PrimitiveListTreeModel.this.synchronizeList();
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java
deleted file mode 100644
index 1caee488c8..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/RadioButtonModelAdapter.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import org.eclipse.jpt.utility.internal.BidiFilter;
-import org.eclipse.jpt.utility.internal.BidiTransformer;
-import org.eclipse.jpt.utility.internal.model.value.FilteringWritablePropertyValueModel;
-import org.eclipse.jpt.utility.internal.model.value.TransformationWritablePropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.ButtonModel can be used to keep a listener
- * (e.g. a JRadioButton) in synch with a (typically shared)
- * PropertyValueModel that holds one value out of a set of values.
- *
- * NOTE: Do *not* use this model with a ButtonGroup, since the
- * shared value holder and the wrappers built by this adapter will
- * keep the appropriate radio button checked. Also, this allows
- * us to uncheck all the radio buttons in a group when the shared
- * value is null.
- */
-public class RadioButtonModelAdapter
- extends ToggleButtonModelAdapter
-{
-
- // ********** constructors **********
-
- /**
- * Constructor - the value holder is required.
- */
- public RadioButtonModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object buttonValue, boolean defaultValue) {
- super(buildBooleanHolder(valueHolder, buttonValue), defaultValue);
- }
-
- /**
- * Constructor - the value holder is required.
- * The default value will be false.
- */
- public RadioButtonModelAdapter(WritablePropertyValueModel<Object> valueHolder, Object buttonValue) {
- super(buildBooleanHolder(valueHolder, buttonValue));
- }
-
-
- // ********** static methods **********
-
- /**
- * Build up a set of wrappers that will convert the
- * specified value holder and button value to/from a boolean.
- *
- * If the value holder's value matches the button value,
- * the wrapper will return true. Likewise, if the value holder's
- * value is set to true, the wrapper will set the value holder's
- * value to the button value.
- */
- public static WritablePropertyValueModel<Boolean> buildBooleanHolder(WritablePropertyValueModel<Object> valueHolder, Object buttonValue) {
- WritablePropertyValueModel<Object> filteringPVM = new FilteringWritablePropertyValueModel<Object>(valueHolder, new RadioButtonFilter(buttonValue));
- return new TransformationWritablePropertyValueModel<Object, Boolean>(filteringPVM, new RadioButtonTransformer(buttonValue));
- }
-
-
- // ********** overrides **********
-
- /**
- * The user cannot de-select a radio button - the user
- * can only *select* a radio button. Only the model can
- * cause a radio button to be de-selected. We use the
- * ARMED flag to indicate whether we are being de-selected
- * by the user.
- */
- @Override
- public void setSelected(boolean b) {
- // do not allow the user to de-select a radio button
- // radio buttons can
- if ((b == false) && this.isArmed()) {
- return;
- }
- super.setSelected(b);
- }
-
-
- // ********** inner classes **********
-
- /**
- * This filter will only pass through a new value to the wrapped
- * value holder when it matches the configured button value.
- */
- public static class RadioButtonFilter implements BidiFilter<Object> {
- private Object buttonValue;
-
- public RadioButtonFilter(Object buttonValue) {
- super();
- this.buttonValue = buttonValue;
- }
-
- /**
- * always return the wrapped value
- */
- public boolean accept(Object value) {
- return true;
- }
-
- /**
- * pass through the value to the wrapped property value model
- * *only* when it matches our button value
- */
- public boolean reverseAccept(Object value) {
- return value == this.buttonValue;
- }
-
- }
-
- /**
- * This transformer will convert the wrapped value to Boolean.TRUE
- * when it matches the configured button value.
- */
- public static class RadioButtonTransformer implements BidiTransformer<Object, Boolean> {
- private Object buttonValue;
-
- public RadioButtonTransformer(Object buttonValue) {
- super();
- this.buttonValue = buttonValue;
- }
-
- /**
- * if the wrapped value matches our button value return true,
- * if it is some other value return false;
- * but if it is null simply pass it through because it will cause the
- * button model's default value to be used
- */
- public Boolean transform(Object value) {
- return (value == null) ? null : Boolean.valueOf(value == this.buttonValue);
- }
-
- /**
- * if the new value is true, pass through the our button value;
- * otherwise pass through null
- */
- public Object reverseTransform(Boolean value) {
- return (value.booleanValue()) ? this.buttonValue : null;
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java
deleted file mode 100644
index c26f18fc90..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/SpinnerModelAdapter.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import javax.swing.AbstractSpinnerModel;
-import javax.swing.SpinnerModel;
-import javax.swing.SpinnerNumberModel;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.SpinnerModel can be used to keep a ChangeListener
- * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a value.
- *
- * Note: it is likely you want to use one of the following classes instead of
- * this one:
- * DateSpinnerModelAdapter
- * NumberSpinnerModelAdapter
- * ListSpinnerModelAdapter
- *
- * NB: This model should only be used for values that have a fairly
- * inexpensive #equals() implementation.
- * @see #synchronizeDelegate(Object)
- */
-public class SpinnerModelAdapter
- extends AbstractSpinnerModel
-{
- /** The delegate spinner model whose behavior we "enhance". */
- protected final SpinnerModel delegate;
-
- /** A listener that allows us to forward any changes made to the delegate spinner model. */
- protected final ChangeListener delegateListener;
-
- /** A value model on the underlying value. */
- protected final WritablePropertyValueModel<Object> valueHolder;
-
- /** A listener that allows us to synchronize with changes made to the underlying value. */
- protected final PropertyChangeListener valueListener;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the value holder and delegate are required.
- */
- public SpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder, SpinnerModel delegate) {
- super();
- if (valueHolder == null || delegate == null) {
- throw new NullPointerException();
- }
- this.valueHolder = valueHolder;
- this.delegate = delegate;
- // postpone listening to the underlying value
- // until we have listeners ourselves...
- this.valueListener = this.buildValueListener();
- this.delegateListener = this.buildDelegateListener();
- }
-
- /**
- * Constructor - the value holder is required.
- * This will wrap a simple number spinner model.
- */
- public SpinnerModelAdapter(WritablePropertyValueModel<Object> valueHolder) {
- this(valueHolder, new SpinnerNumberModel());
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildValueListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildValueListener_());
- }
-
- protected PropertyChangeListener buildValueListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- SpinnerModelAdapter.this.valueChanged(event);
- }
- @Override
- public String toString() {
- return "value listener";
- }
- };
- }
-
- /**
- * expand access a bit for inner class
- */
- @Override
- protected void fireStateChanged() {
- super.fireStateChanged();
- }
-
- protected ChangeListener buildDelegateListener() {
- return new ChangeListener() {
- public void stateChanged(ChangeEvent event) {
- // forward the event, with this as the source
- SpinnerModelAdapter.this.fireStateChanged();
- }
- @Override
- public String toString() {
- return "delegate listener";
- }
- };
- }
-
-
- // ********** SpinnerModel implementation **********
-
- public Object getValue() {
- return this.delegate.getValue();
- }
-
- /**
- * Extend to update the underlying value directly.
- * The resulting event will be ignored: @see #synchronizeDelegate(Object).
- */
- public void setValue(Object value) {
- this.delegate.setValue(value);
- this.valueHolder.setValue(value);
- }
-
- public Object getNextValue() {
- return this.delegate.getNextValue();
- }
-
- public Object getPreviousValue() {
- return this.delegate.getPreviousValue();
- }
-
- /**
- * Extend to start listening to the underlying value if necessary.
- */
- @Override
- public void addChangeListener(ChangeListener listener) {
- if (this.listenerList.getListenerCount(ChangeListener.class) == 0) {
- this.delegate.addChangeListener(this.delegateListener);
- this.engageValueHolder();
- }
- super.addChangeListener(listener);
- }
-
- /**
- * Extend to stop listening to the underlying value if appropriate.
- */
- @Override
- public void removeChangeListener(ChangeListener listener) {
- super.removeChangeListener(listener);
- if (this.listenerList.getListenerCount(ChangeListener.class) == 0) {
- this.disengageValueHolder();
- this.delegate.removeChangeListener(this.delegateListener);
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * A third party has modified the underlying value.
- * Synchronize the delegate model accordingly.
- */
- protected void valueChanged(PropertyChangeEvent event) {
- this.synchronizeDelegate(event.getNewValue());
- }
-
- /**
- * Set the delegate's value if it has changed.
- */
- protected void synchronizeDelegate(Object value) {
- // check to see whether the delegate has already been synchronized
- // (via #setValue())
- if ( ! this.delegate.getValue().equals(value)) {
- this.delegate.setValue(value);
- }
- }
-
- protected void engageValueHolder() {
- this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
- this.synchronizeDelegate(this.valueHolder.getValue());
- }
-
- protected void disengageValueHolder() {
- this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.valueHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java
deleted file mode 100644
index 5e039e270b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TableModelAdapter.java
+++ /dev/null
@@ -1,410 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.AbstractTableModel;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTListChangeListenerWrapper;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.internal.model.value.CollectionListValueModelAdapter;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.CollectionValueModel;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This TableModel can be used to keep a TableModelListener (e.g. a JTable)
- * in synch with a ListValueModel that holds a collection of model objects,
- * each of which corresponds to a row in the table.
- * Typically, each column of the table will be bound to a different aspect
- * of the contained model objects.
- *
- * For example, a MWTable has an attribute 'databaseFields' that holds
- * a collection of MWDatabaseFields that would correspond to the rows of
- * a JTable; and each MWDatabaseField has a number
- * of attributes (e.g. name, type, size) that can be bound to the columns of
- * a row in the JTable. As these database fields are added, removed, and
- * changed, this model will keep the listeners aware of the changes.
- *
- * An instance of this TableModel must be supplied with a
- * list holder (e.g. the 'databaseFields'), which is a value
- * model on the bound collection This is required - the
- * collection itself can be null, but the list value model that
- * holds it is required. Typically this list will be sorted (@see
- * SortedListValueModelAdapter).
- *
- * This TableModel must also be supplied with a ColumnAdapter that
- * will be used to configure the headers, renderers, editors, and contents
- * of the various columns.
- *
- * Design decision:
- * Cell listener options (from low space/high time to high space/low time):
- * - 1 cell listener listening to every cell (this is the current implementation)
- * - 1 cell listener per row
- * - 1 cell listener per cell
- */
-public class TableModelAdapter<E>
- extends AbstractTableModel
-{
- /**
- * a list of user objects that are converted to
- * rows via the column adapter
- */
- private ListValueModel<? extends E> listHolder;
- private final ListChangeListener listChangeListener;
-
- /**
- * each row is an array of cell models
- */
- // declare as ArrayList so we can use #ensureCapacity(int)
- private final ArrayList<WritablePropertyValueModel<Object>[]> rows;
-
- /**
- * client-supplied adapter that provides with the various column
- * settings and converts the objects in the LVM
- * into an array of cell models
- */
- private final ColumnAdapter columnAdapter;
-
- /**
- * the single listener that listens to every cell's model
- */
- private final PropertyChangeListener cellListener;
-
-
- // ********** constructors **********
-
- /**
- * Construct a table model adapter for the specified objects
- * and adapter.
- */
- public TableModelAdapter(ListValueModel<? extends E> listHolder, ColumnAdapter columnAdapter) {
- super();
- if (listHolder == null) {
- throw new NullPointerException();
- }
- this.listHolder = listHolder;
- this.columnAdapter = columnAdapter;
- this.listChangeListener = this.buildListChangeListener();
- this.rows = new ArrayList<WritablePropertyValueModel<Object>[]>();
- this.cellListener = this.buildCellListener();
- }
-
- /**
- * Construct a table model adapter for the specified objects
- * and adapter.
- */
- public TableModelAdapter(CollectionValueModel<? extends E> collectionHolder, ColumnAdapter columnAdapter) {
- this(new CollectionListValueModelAdapter<E>(collectionHolder), columnAdapter);
- }
-
-
- // ********** initialization **********
-
- protected ListChangeListener buildListChangeListener() {
- return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
- }
-
- protected ListChangeListener buildListChangeListener_() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- TableModelAdapter.this.addRows(event.getIndex(), event.itemsSize(), this.items(event));
- }
- public void itemsRemoved(ListChangeEvent event) {
- TableModelAdapter.this.removeRows(event.getIndex(), event.itemsSize());
- }
- public void itemsReplaced(ListChangeEvent event) {
- TableModelAdapter.this.replaceRows(event.getIndex(), this.items(event));
- }
- public void itemsMoved(ListChangeEvent event) {
- TableModelAdapter.this.moveRows(event.getTargetIndex(), event.getSourceIndex(), event.getMoveLength());
- }
- public void listCleared(ListChangeEvent event) {
- TableModelAdapter.this.clearTable();
- }
- public void listChanged(ListChangeEvent event) {
- TableModelAdapter.this.rebuildTable();
- }
- /**
- * minimize scope of suppressed warnings
- */
- @SuppressWarnings("unchecked")
- protected Iterator<Object> items(ListChangeEvent event) {
- return (Iterator<Object>) event.items();
- }
- @Override
- public String toString() {
- return "list listener";
- }
- };
- }
-
-
- protected PropertyChangeListener buildCellListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildCellListener_());
- }
-
- protected PropertyChangeListener buildCellListener_() {
- return new PropertyChangeListener() {
- @SuppressWarnings("unchecked")
- public void propertyChanged(PropertyChangeEvent event) {
- TableModelAdapter.this.cellChanged((WritablePropertyValueModel<Object>) event.getSource());
- }
- @Override
- public String toString() {
- return "cell listener";
- }
- };
- }
-
-
- // ********** TableModel implementation **********
-
- public int getColumnCount() {
- return this.columnAdapter.columnCount();
- }
-
- public int getRowCount() {
- return this.rows.size();
- }
-
- @Override
- public String getColumnName(int column) {
- return this.columnAdapter.columnName(column);
- }
-
- @Override
- public Class<?> getColumnClass(int columnIndex) {
- return this.columnAdapter.columnClass(columnIndex);
- }
-
- @Override
- public boolean isCellEditable(int rowIndex, int columnIndex) {
- return this.columnAdapter.columnIsEditable(columnIndex);
- }
-
- public Object getValueAt(int rowIndex, int columnIndex) {
- WritablePropertyValueModel<Object>[] row = this.rows.get(rowIndex);
- return row[columnIndex].getValue();
- }
-
- @Override
- public void setValueAt(Object value, int rowIndex, int columnIndex) {
- WritablePropertyValueModel<Object>[] row = this.rows.get(rowIndex);
- row[columnIndex].setValue(value);
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public void addTableModelListener(TableModelListener l) {
- if (this.hasNoTableModelListeners()) {
- this.engageModel();
- }
- super.addTableModelListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model if necessary.
- */
- @Override
- public void removeTableModelListener(TableModelListener l) {
- super.removeTableModelListener(l);
- if (this.hasNoTableModelListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** public API **********
-
- /**
- * Return the underlying list model.
- */
- public ListValueModel<? extends E> getModel() {
- return this.listHolder;
- }
-
- /**
- * Set the underlying list model.
- */
- public void setModel(ListValueModel<E> listHolder) {
- if (listHolder == null) {
- throw new NullPointerException();
- }
- boolean hasListeners = this.hasTableModelListeners();
- if (hasListeners) {
- this.disengageModel();
- }
- this.listHolder = listHolder;
- if (hasListeners) {
- this.engageModel();
- this.fireTableDataChanged();
- }
- }
-
- /**
- * Set the underlying collection model.
- */
- public void setModel(CollectionValueModel<E> collectionHolder) {
- this.setModel(new CollectionListValueModelAdapter<E>(collectionHolder));
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether this model has no listeners.
- */
- protected boolean hasNoTableModelListeners() {
- return this.listenerList.getListenerCount(TableModelListener.class) == 0;
- }
-
- /**
- * Return whether this model has any listeners.
- */
- protected boolean hasTableModelListeners() {
- return ! this.hasNoTableModelListeners();
- }
-
-
- // ********** behavior **********
-
- /**
- * Start listening to the list of objects and the various aspects
- * of the objects that make up the rows.
- */
- private void engageModel() {
- this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- this.engageAllCells();
- }
-
- /**
- * Convert the objects into rows and listen to the cells.
- */
- private void engageAllCells() {
- this.rows.ensureCapacity(this.listHolder.size());
- for (Iterator<? extends E> stream = this.listHolder.iterator(); stream.hasNext(); ) {
- WritablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(stream.next());
- this.engageRow(row);
- this.rows.add(row);
- }
- }
-
- /**
- * Listen to the cells in the specified row.
- */
- private void engageRow(WritablePropertyValueModel<Object>[] row) {
- for (int i = row.length; i-- > 0; ) {
- row[i].addPropertyChangeListener(PropertyValueModel.VALUE, this.cellListener);
- }
- }
-
- /**
- * Stop listening.
- */
- private void disengageModel() {
- this.disengageAllCells();
- this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
- }
-
- private void disengageAllCells() {
- for (WritablePropertyValueModel<Object>[] row : this.rows) {
- this.disengageRow(row);
- }
- this.rows.clear();
- }
-
- private void disengageRow(WritablePropertyValueModel<Object>[] row) {
- for (int i = row.length; i-- > 0; ) {
- row[i].removePropertyChangeListener(PropertyValueModel.VALUE, this.cellListener);
- }
- }
-
- /**
- * brute-force search for the cell(s) that changed...
- */
- void cellChanged(WritablePropertyValueModel<Object> cellHolder) {
- for (int i = this.rows.size(); i-- > 0; ) {
- WritablePropertyValueModel<Object>[] row = this.rows.get(i);
- for (int j = row.length; j-- > 0; ) {
- if (row[j] == cellHolder) {
- this.fireTableCellUpdated(i, j);
- }
- }
- }
- }
-
- /**
- * convert the items to rows
- */
- void addRows(int index, int size, Iterator<Object> items) {
- List<WritablePropertyValueModel<Object>[]> newRows = new ArrayList<WritablePropertyValueModel<Object>[]>(size);
- while (items.hasNext()) {
- WritablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(items.next());
- this.engageRow(row);
- newRows.add(row);
- }
- this.rows.addAll(index, newRows);
- this.fireTableRowsInserted(index, index + size - 1);
- }
-
- void removeRows(int index, int size) {
- for (int i = 0; i < size; i++) {
- this.disengageRow(this.rows.remove(index));
- }
- this.fireTableRowsDeleted(index, index + size - 1);
- }
-
- void replaceRows(int index, Iterator<Object> items) {
- int i = index;
- while (items.hasNext()) {
- WritablePropertyValueModel<Object>[] row = this.rows.get(i);
- this.disengageRow(row);
- row = this.columnAdapter.cellModels(items.next());
- this.engageRow(row);
- this.rows.set(i, row);
- i++;
- }
- this.fireTableRowsUpdated(index, i - 1);
- }
-
- void moveRows(int targetIndex, int sourceIndex, int length) {
- ArrayList<WritablePropertyValueModel<Object>[]> temp = new ArrayList<WritablePropertyValueModel<Object>[]>(length);
- for (int i = 0; i < length; i++) {
- temp.add(this.rows.remove(sourceIndex));
- }
- this.rows.addAll(targetIndex, temp);
-
- int start = Math.min(targetIndex, sourceIndex);
- int end = Math.max(targetIndex, sourceIndex) + length - 1;
- this.fireTableRowsUpdated(start, end);
- }
-
- void clearTable() {
- this.disengageAllCells();
- this.fireTableDataChanged();
- }
-
- void rebuildTable() {
- this.disengageAllCells();
- this.engageAllCells();
- this.fireTableDataChanged();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java
deleted file mode 100644
index 7c0e742f33..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/ToggleButtonModelAdapter.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.awt.event.ActionListener;
-import java.awt.event.ItemListener;
-import javax.swing.JToggleButton.ToggleButtonModel;
-import javax.swing.event.ChangeListener;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
-
-/**
- * This javax.swing.ButtonModel can be used to keep a listener
- * (e.g. a JCheckBox or a JRadioButton) in synch with a PropertyValueModel
- * on a boolean.
- */
-public class ToggleButtonModelAdapter
- extends ToggleButtonModel
-{
- /**
- * The default setting for the toggle button; for when the underlying model is null.
- * The default [default value] is false (i.e. the toggle button is unchecked/empty).
- */
- protected final boolean defaultValue;
-
- /** A value model on the underlying model boolean. */
- protected final WritablePropertyValueModel<Boolean> booleanHolder;
-
- /**
- * A listener that allows us to synchronize with
- * changes made to the underlying model boolean.
- */
- protected final PropertyChangeListener booleanChangeListener;
-
-
- // ********** constructors **********
-
- /**
- * Constructor - the boolean holder is required.
- */
- public ToggleButtonModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) {
- super();
- if (booleanHolder == null) {
- throw new NullPointerException();
- }
- this.booleanHolder = booleanHolder;
- this.booleanChangeListener = this.buildBooleanChangeListener();
- // postpone listening to the underlying model
- // until we have listeners ourselves...
- this.defaultValue = defaultValue;
- }
-
- /**
- * Constructor - the boolean holder is required.
- * The default value will be false.
- */
- public ToggleButtonModelAdapter(WritablePropertyValueModel<Boolean> booleanHolder) {
- this(booleanHolder, false);
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildBooleanChangeListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildBooleanChangeListener_());
- }
-
- protected PropertyChangeListener buildBooleanChangeListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- ToggleButtonModelAdapter.this.booleanChanged(event);
- }
- @Override
- public String toString() {
- return "boolean listener";
- }
- };
- }
-
-
- // ********** ButtonModel implementation **********
-
- /**
- * Extend to update the underlying model if necessary.
- */
- @Override
- public void setSelected(boolean b) {
- if (this.isSelected() != b) { // stop the recursion!
- super.setSelected(b);//put the super call first, otherwise the following gets called twice
- this.booleanHolder.setValue(Boolean.valueOf(b));
- }
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public void addActionListener(ActionListener l) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addActionListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model if appropriate.
- */
- @Override
- public void removeActionListener(ActionListener l) {
- super.removeActionListener(l);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public void addItemListener(ItemListener l) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addItemListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model if appropriate.
- */
- @Override
- public void removeItemListener(ItemListener l) {
- super.removeItemListener(l);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public void addChangeListener(ChangeListener l) {
- if (this.hasNoListeners()) {
- this.engageModel();
- }
- super.addChangeListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model if appropriate.
- */
- @Override
- public void removeChangeListener(ChangeListener l) {
- super.removeChangeListener(l);
- if (this.hasNoListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** queries **********
-
- /**
- * Return whether we have no listeners at all.
- */
- protected boolean hasNoListeners() {
- return this.listenerList.getListenerCount() == 0;
- }
-
- protected boolean getDefaultValue() {
- return this.defaultValue;
- }
-
-
- // ********** behavior **********
-
- /**
- * Synchronize with the specified value.
- * If it is null, use the default value (which is typically false).
- */
- protected void setSelected(Boolean value) {
- if (value == null) {
- this.setSelected(this.getDefaultValue());
- } else {
- this.setSelected(value.booleanValue());
- }
- }
-
- /**
- * The underlying model has changed - synchronize accordingly.
- */
- protected void booleanChanged(PropertyChangeEvent event) {
- this.setSelected((Boolean) event.getNewValue());
- }
-
- protected void engageModel() {
- this.booleanHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener);
- this.setSelected(this.booleanHolder.getValue());
- }
-
- protected void disengageModel() {
- this.booleanHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener);
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.booleanHolder);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java
deleted file mode 100644
index f94a723025..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/model/value/swing/TreeModelAdapter.java
+++ /dev/null
@@ -1,722 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.model.value.swing;
-
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import javax.swing.event.TreeModelListener;
-import javax.swing.tree.TreePath;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTListChangeListenerWrapper;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTPropertyChangeListenerWrapper;
-import org.eclipse.jpt.utility.internal.model.listener.awt.AWTStateChangeListenerWrapper;
-import org.eclipse.jpt.utility.internal.model.value.StaticPropertyValueModel;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.value.ListValueModel;
-import org.eclipse.jpt.utility.model.value.PropertyValueModel;
-import org.eclipse.jpt.utility.model.value.TreeNodeValueModel;
-
-/**
- * This javax.swing.tree.TreeModel can be used to keep a TreeModelListener
- * (e.g. a JTree) in synch with a tree of TreeNodeValueModel objects. Unlike
- * javax.swing.tree.DefaultTreeModel, you do not add and remove nodes with
- * methods implemented here. You can add and remove nodes by adding and
- * removing them directly to/from the nodes (or, more typically, the domain
- * objects the nodes are wrapping and listening to).
- *
- * Due to limitations in JTree, the root of the tree can never be null,
- * which, typically, should not be a problem. (If you want to display an empty
- * tree you can set the JTree's treeModel to null.)
- */
-public class TreeModelAdapter<T>
- extends AbstractTreeModel
-{
- /**
- * A value model on the underlying tree's root node and its
- * corresponding listener. This allows clients to swap out
- * the entire tree. Due to limitations in JTree, the root should
- * never be set to null while we have listeners.
- */
- private final PropertyValueModel<TreeNodeValueModel<T>> rootHolder;
- private final PropertyChangeListener rootListener;
-
- /**
- * A listener that notifies us when a node's internal
- * "state" changes (as opposed to the node's value or list of
- * children), allowing us to forward notification to our listeners.
- */
- private final StateChangeListener nodeStateListener;
-
- /**
- * A listener that notifies us when a node's "value"
- * changes (as opposed to the node's state or list of
- * children), allowing us to forward notification to our listeners.
- * Typically, this will only happen with nodes that hold
- * primitive data.
- */
- private final PropertyChangeListener nodeValueListener;
-
- /**
- * A listener that notifies us when an underlying node's
- * "list" of children changes, allowing us to keep our
- * internal tree in synch with the underlying tree model.
- */
- private final ListChangeListener childrenListener;
-
- /* these attributes make up our internal tree */
- /**
- * The root cannot be null while we have listeners, which is
- * most of the time. The root is cached so we can disengage
- * from it when it has been swapped out.
- */
- private TreeNodeValueModel<T> root;
-
- /**
- * Map the nodes to their lists of children.
- * We cache these so we can swap out the entire list of children
- * when we receive a #listChanged() event (which does not include
- * the items that were affected).
- * @see EventChangePolicy#rebuildChildren()
- */
- final IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>> childrenLists;
-
- /**
- * Map the children models to their parents.
- * We cache these so we can figure out the "real" source of the
- * list change events (the parent).
- * @see EventChangePolicy#parent()
- */
- final IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>> parents;
-
-
- // ********** constructors **********
-
- /**
- * Construct a tree model for the specified root.
- */
- public TreeModelAdapter(PropertyValueModel<TreeNodeValueModel<T>> rootHolder) {
- super();
- if (rootHolder == null) {
- throw new NullPointerException();
- }
- this.rootHolder = rootHolder;
- this.rootListener = this.buildRootListener();
- this.nodeStateListener = this.buildNodeStateListener();
- this.nodeValueListener = this.buildNodeValueListener();
- this.childrenListener = this.buildChildrenListener();
- this.childrenLists = new IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>>();
- this.parents = new IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>>();
- }
-
- /**
- * Construct a tree model for the specified root.
- */
- public TreeModelAdapter(TreeNodeValueModel<T> root) {
- this(new StaticPropertyValueModel<TreeNodeValueModel<T>>(root));
- }
-
-
- // ********** initialization **********
-
- protected PropertyChangeListener buildRootListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildRootListener_());
- }
-
- protected PropertyChangeListener buildRootListener_() {
- return new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent event) {
- TreeModelAdapter.this.rootChanged();
- }
- @Override
- public String toString() {
- return "root listener";
- }
- };
- }
-
- protected PropertyChangeListener buildNodeValueListener() {
- return new AWTPropertyChangeListenerWrapper(this.buildNodeValueListener_());
- }
-
- protected PropertyChangeListener buildNodeValueListener_() {
- return new PropertyChangeListener() {
- @SuppressWarnings("unchecked")
- public void propertyChanged(PropertyChangeEvent event) {
- TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) event.getSource());
- }
- @Override
- public String toString() {
- return "node value listener";
- }
- };
- }
-
- protected StateChangeListener buildNodeStateListener() {
- return new AWTStateChangeListenerWrapper(this.buildNodeStateListener_());
- }
-
- protected StateChangeListener buildNodeStateListener_() {
- return new StateChangeListener() {
- @SuppressWarnings("unchecked")
- public void stateChanged(StateChangeEvent event) {
- TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) event.getSource());
- }
- @Override
- public String toString() {
- return "node state listener";
- }
- };
- }
-
- protected ListChangeListener buildChildrenListener() {
- return new AWTListChangeListenerWrapper(this.buildChildrenListener_());
- }
-
- protected ListChangeListener buildChildrenListener_() {
- return new ListChangeListener() {
- public void itemsAdded(ListChangeEvent event) {
- new EventChangePolicy(event).addChildren();
- }
- public void itemsRemoved(ListChangeEvent event) {
- new EventChangePolicy(event).removeChildren();
- }
- public void itemsReplaced(ListChangeEvent event) {
- new EventChangePolicy(event).replaceChildren();
- }
- public void itemsMoved(ListChangeEvent event) {
- new EventChangePolicy(event).moveChildren();
- }
- public void listCleared(ListChangeEvent event) {
- new EventChangePolicy(event).clearChildren();
- }
- public void listChanged(ListChangeEvent event) {
- new EventChangePolicy(event).rebuildChildren();
- }
- @Override
- public String toString() {
- return "children listener";
- }
- };
- }
-
-
- // ********** TreeModel implementation **********
-
- public Object getRoot() {
- return this.root;
- }
-
- @SuppressWarnings("unchecked")
- public Object getChild(Object parent, int index) {
- return ((TreeNodeValueModel<T>) parent).child(index);
- }
-
- @SuppressWarnings("unchecked")
- public int getChildCount(Object parent) {
- return ((TreeNodeValueModel<T>) parent).childrenSize();
- }
-
- @SuppressWarnings("unchecked")
- public boolean isLeaf(Object node) {
- return ((TreeNodeValueModel<T>) node).isLeaf();
- }
-
- @SuppressWarnings("unchecked")
- public void valueForPathChanged(TreePath path, Object newValue) {
- ((TreeNodeValueModel<T>) path.getLastPathComponent()).setValue((T) newValue);
- }
-
- @SuppressWarnings("unchecked")
- public int getIndexOfChild(Object parent, Object child) {
- return ((TreeNodeValueModel<T>) parent).indexOfChild((TreeNodeValueModel<T>) child);
- }
-
- /**
- * Extend to start listening to the underlying model if necessary.
- */
- @Override
- public void addTreeModelListener(TreeModelListener l) {
- if (this.hasNoTreeModelListeners()) {
- this.engageModel();
- }
- super.addTreeModelListener(l);
- }
-
- /**
- * Extend to stop listening to the underlying model if appropriate.
- */
- @Override
- public void removeTreeModelListener(TreeModelListener l) {
- super.removeTreeModelListener(l);
- if (this.hasNoTreeModelListeners()) {
- this.disengageModel();
- }
- }
-
-
- // ********** behavior **********
-
- /**
- * Listen to the root and all the other nodes
- * in the underlying tree model.
- */
- private void engageModel() {
- this.rootHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.rootListener);
- this.root = this.rootHolder.getValue();
- if (this.root == null) {
- throw new NullPointerException(); // the root cannot be null while we have listeners
- }
- this.engageNode(this.root);
- this.addRoot();
- }
-
- /**
- * Add the root and all of the nodes to the underlying tree.
- */
- private void addRoot() {
- this.addNode(0, this.root);
- }
-
- /**
- * Stop listening to the root and all the other
- * nodes in the underlying tree model.
- */
- private void disengageModel() {
- this.removeRoot();
- this.disengageNode(this.root);
- this.root = null;
- this.rootHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.rootListener);
- }
-
- /**
- * Remove the root and all of the nodes from the underlying tree.
- */
- private void removeRoot() {
- this.removeNode(0, this.root);
- }
-
- /**
- * The root has been swapped.
- * This method is a bit gnarly because the API for notifying listeners
- * that the root has changed is a bit inconsistent with that used for
- * non-root nodes.
- */
- void rootChanged() {
- TreeNodeValueModel<T> newRoot = this.rootHolder.getValue();
- if (newRoot == null) {
- throw new NullPointerException(); // the root cannot be null while we have listeners
- }
- // remove all the current root's children from the tree
- // and remove the it from the internal tree
- this.removeRoot();
-
- // save the old root and swap in the new root
- TreeNodeValueModel<T> oldRoot = this.root;
- this.root = newRoot;
-
- // we must be listening to both the old and new roots when we fire the event
- // because their values can be affected by whether they have listeners
- this.engageNode(this.root);
- this.fireTreeRootReplaced(this.root);
- // now we can stop listening to the old root
- this.disengageNode(oldRoot);
-
- // add the new root to the internal tree and
- // add all its children to the tree also
- this.addRoot();
- }
-
- /**
- * Either the "value" or the "state" of the specified node has changed,
- * forward notification to our listeners.
- */
- void nodeChanged(TreeNodeValueModel<T> node) {
- TreeNodeValueModel<T> parent = node.parent();
- if (parent == null) {
- this.fireTreeRootChanged(node);
- } else {
- this.fireTreeNodeChanged(parent.path(), parent.indexOfChild(node), node);
- }
- }
-
- /**
- * Listen to the nodes, notify our listeners that the nodes were added,
- * and then add the nodes to our internal tree.
- * We must listen to the nodes before notifying anybody, because
- * adding a listener can change the value of a node.
- */
- void addChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) {
- int len = childIndices.length;
- for (int i = 0; i < len; i++) {
- this.engageNode(children[i]);
- }
- this.fireTreeNodesInserted(path, childIndices, children);
- for (int i = 0; i < len; i++) {
- this.addNode(childIndices[i], children[i]);
- }
- }
-
- /**
- * Listen to the node and its children model.
- */
- private void engageNode(TreeNodeValueModel<T> node) {
- node.addStateChangeListener(this.nodeStateListener);
- node.addPropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener);
- node.childrenModel().addListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener);
- }
-
- /**
- * Add the node to our internal tree;
- * then recurse down through the node's children,
- * adding them to the internal tree also.
- */
- private void addNode(int index, TreeNodeValueModel<T> node) {
- this.addNodeToInternalTree(node.parent(), index, node, node.childrenModel());
- new NodeChangePolicy(node).addChildren();
- }
-
- /**
- * Add the specified node to our internal tree.
- */
- private void addNodeToInternalTree(TreeNodeValueModel<T> parent, int index, TreeNodeValueModel<T> node, ListValueModel<TreeNodeValueModel<T>> childrenModel) {
- List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent);
- if (siblings == null) {
- siblings = new ArrayList<TreeNodeValueModel<T>>();
- this.childrenLists.put(parent, siblings);
- }
- siblings.add(index, node);
-
- this.parents.put(childrenModel, node);
- }
-
- /**
- * Remove nodes from our internal tree, notify our listeners that the
- * nodes were removed, then stop listening to the nodes.
- * We must listen to the nodes until after notifying anybody, because
- * removing a listener can change the value of a node.
- */
- void removeChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) {
- int len = childIndices.length;
- for (int i = 0; i < len; i++) {
- // the indices slide down a notch each time we remove a child
- this.removeNode(childIndices[i] - i, children[i]);
- }
- this.fireTreeNodesRemoved(path, childIndices, children);
- for (int i = 0; i < len; i++) {
- this.disengageNode(children[i]);
- }
- }
-
- /**
- * First, recurse down through the node's children,
- * removing them from our internal tree;
- * then remove the node itself from our internal tree.
- */
- private void removeNode(int index, TreeNodeValueModel<T> node) {
- new NodeChangePolicy(node).removeChildren();
- this.removeNodeFromInternalTree(node.parent(), index, node, node.childrenModel());
- }
-
- /**
- * Remove the specified node from our internal tree.
- */
- private void removeNodeFromInternalTree(TreeNodeValueModel<T> parent, int index, TreeNodeValueModel<T> node, ListValueModel<TreeNodeValueModel<T>> childrenModel) {
- this.parents.remove(childrenModel);
-
- List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent);
- siblings.remove(index);
- if (siblings.isEmpty()) {
- this.childrenLists.remove(parent);
- }
- }
-
- /**
- * Stop listening to the node and its children model.
- */
- private void disengageNode(TreeNodeValueModel<T> node) {
- node.childrenModel().removeListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener);
- node.removePropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener);
- node.removeStateChangeListener(this.nodeStateListener);
- }
-
- void moveChildren(TreeNodeValueModel<T> parent, int targetIndex, int sourceIndex, int length) {
- List<TreeNodeValueModel<T>> childrenList = this.childrenLists.get(parent);
- ArrayList<TreeNodeValueModel<T>> temp = new ArrayList<TreeNodeValueModel<T>>(length);
- for (int i = 0; i < length; i++) {
- temp.add(childrenList.remove(sourceIndex));
- }
- childrenList.addAll(targetIndex, temp);
-
- this.fireTreeStructureChanged(parent.path());
- }
-
-
- // ********** standard methods **********
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.root);
- }
-
-
- // ********** inner classes **********
-
- /**
- * Coalesce some of the common change policy behavior.
- */
- private abstract class ChangePolicy {
-
- ChangePolicy() {
- super();
- }
-
- /**
- * Add the current set of children.
- */
- void addChildren() {
- TreeModelAdapter.this.addChildren(this.parent().path(), this.childIndices(), this.childArray());
- }
-
- /**
- * Remove the current set of children.
- */
- void removeChildren() {
- TreeModelAdapter.this.removeChildren(this.parent().path(), this.childIndices(), this.childArray());
- }
-
- /**
- * Return an array of the indices of the current set of children,
- * which should be contiguous.
- */
- int[] childIndices() {
- return this.buildIndices(this.childrenStartIndex(), this.childrenSize());
- }
-
- /**
- * Return an array of the current set of children.
- */
- TreeNodeValueModel<T>[] childArray() {
- return this.buildArray(this.children(), this.childrenSize());
- }
-
- /**
- * Build an array to hold the elements in the specified iterator.
- * If they are different sizes, something is screwed up...
- */
- TreeNodeValueModel<T>[] buildArray(Iterator<TreeNodeValueModel<T>> stream, int size) {
- @SuppressWarnings("unchecked")
- TreeNodeValueModel<T>[] array = new TreeNodeValueModel[size];
- for (int i = 0; stream.hasNext(); i++) {
- array[i] = stream.next();
- }
- return array;
- }
-
- /**
- * Return a set of indices, starting at zero and
- * continuing for the specified size.
- */
- int[] buildIndices(int size) {
- return buildIndices(0, size);
- }
-
- /**
- * Return a set of indices, starting at the specified index and
- * continuing for the specified size.
- */
- int[] buildIndices(int start, int size) {
- int[] indices = new int[size];
- int index = start;
- for (int i = 0; i < size; i++) {
- indices[i] = index++;
- }
- return indices;
- }
-
- /**
- * Return the parent of the current set of children.
- */
- abstract TreeNodeValueModel<T> parent();
-
- /**
- * Return the starting index for the current set of children.
- */
- abstract int childrenStartIndex();
-
- /**
- * Return the size of the current set of children.
- */
- abstract int childrenSize();
-
- /**
- * Return an interator on the current set of children.
- */
- abstract Iterator<TreeNodeValueModel<T>> children();
-
- }
-
-
- /**
- * Wraps a ListChangeEvent for adding, removing, replacing,
- * and changing children.
- */
- private class EventChangePolicy extends ChangePolicy {
- private ListChangeEvent event;
-
- EventChangePolicy(ListChangeEvent event) {
- this.event = event;
- }
-
- /**
- * Map the ListChangeEvent's source to the corresponding parent.
- */
- @Override
- TreeNodeValueModel<T> parent() {
- return TreeModelAdapter.this.parents.get(this.event.getSource());
- }
-
- /**
- * The ListChangeEvent's item index is the children start index.
- */
- @Override
- int childrenStartIndex() {
- return this.event.getIndex();
- }
-
- /**
- * The ListChangeEvent's size is the children size.
- */
- @Override
- int childrenSize() {
- return this.event.itemsSize();
- }
-
- /**
- * The ListChangeEvent's items are the children.
- */
- @Override
- @SuppressWarnings("unchecked")
- Iterator<TreeNodeValueModel<T>> children() {
- return (Iterator<TreeNodeValueModel<T>>) this.event.items();
- }
-
- /**
- * Remove the old nodes and add the new ones.
- */
- void replaceChildren() {
- TreeNodeValueModel<T>[] parentPath = this.parent().path();
- int[] childIndices = this.childIndices();
- TreeModelAdapter.this.removeChildren(parentPath, childIndices, this.replacedChildren());
- TreeModelAdapter.this.addChildren(parentPath, childIndices, this.childArray());
- }
-
- /**
- * Remove the old nodes and add the new ones.
- */
- void moveChildren() {
- TreeModelAdapter.this.moveChildren(this.parent(), this.event.getTargetIndex(), this.event.getSourceIndex(), this.event.getMoveLength());
- }
-
- /**
- * Clear all the nodes.
- */
- void clearChildren() {
- TreeNodeValueModel<T> parent = this.parent();
- TreeNodeValueModel<T>[] parentPath = parent.path();
- List<TreeNodeValueModel<T>> childrenList = TreeModelAdapter.this.childrenLists.get(parent);
- int[] childIndices = this.buildIndices(childrenList.size());
- TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList.iterator(), childrenList.size());
- TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray);
- }
-
- /**
- * Remove all the old nodes and add all the new nodes.
- */
- void rebuildChildren() {
- TreeNodeValueModel<T> parent = this.parent();
- TreeNodeValueModel<T>[] parentPath = parent.path();
- List<TreeNodeValueModel<T>> childrenList = TreeModelAdapter.this.childrenLists.get(parent);
- int[] childIndices = this.buildIndices(childrenList.size());
- TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList.iterator(), childrenList.size());
- TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray);
-
- childIndices = this.buildIndices(parent.childrenModel().size());
- childArray = this.buildArray(parent.childrenModel().iterator(), parent.childrenSize());
- TreeModelAdapter.this.addChildren(parentPath, childIndices, childArray);
- }
-
- /**
- * The ListChangeEvent's replaced items are the replaced children.
- */
- @SuppressWarnings("unchecked")
- TreeNodeValueModel<T>[] replacedChildren() {
- return this.buildArray((Iterator<TreeNodeValueModel<T>>) this.event.replacedItems(), this.event.itemsSize());
- }
-
- }
-
-
- /**
- * Wraps a TreeNodeValueModel for adding and removing its children.
- */
- private class NodeChangePolicy extends ChangePolicy {
- private TreeNodeValueModel<T> node;
-
- NodeChangePolicy(TreeNodeValueModel<T> node) {
- this.node = node;
- }
-
- /**
- * The node itself is the parent.
- */
- @Override
- TreeNodeValueModel<T> parent() {
- return this.node;
- }
-
- /**
- * Since we will always be dealing with all of the node's
- * children, the children start index is always zero.
- */
- @Override
- int childrenStartIndex() {
- return 0;
- }
-
- /**
- * Since we will always be dealing with all of the node's
- * children, the children size is always equal to the size
- * of the children model.
- */
- @Override
- int childrenSize() {
- return this.node.childrenModel().size();
- }
-
- /**
- * Since we will always be dealing with all of the node's
- * children, the children are all the objects held by
- * the children model.
- */
- @Override
- Iterator<TreeNodeValueModel<T>> children() {
- return this.node.childrenModel().iterator();
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java
deleted file mode 100644
index a7fab12bdb..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AbstractNode.java
+++ /dev/null
@@ -1,939 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import java.util.Vector;
-import org.eclipse.jpt.utility.internal.iterators.CloneIterator;
-import org.eclipse.jpt.utility.internal.iterators.CloneListIterator;
-import org.eclipse.jpt.utility.internal.iterators.FilteringIterator;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.jpt.utility.internal.model.CallbackChangeSupport;
-import org.eclipse.jpt.utility.internal.model.ChangeSupport;
-
-/**
- * Base class for Node classes.
- * Provides support for the following:
- * initialization
- * enforced object identity wrt #equals()/#hashCode()
- * containment hierarchy (parent/child)
- * user comment
- * dirty flag
- * problems
- * sorting
- *
- * Typically, subclasses should consider implementing the following methods:
- * the appropriate constructors
- * (with the appropriately-restrictive type declaration for parent)
- * #initialize()
- * #initialize(Node parentNode)
- * #checkParent(Node parentNode)
- * #addChildrenTo(List list)
- * #nodeRemoved(Node)
- * #validator()
- * #transientAspectNames() or
- * #addTransientAspectNamesTo(Set transientAspectNames)
- * #addProblemsTo(List currentProblems)
- * #nonValidatedAspectNames()
- * #addNonValidatedAspectNamesTo(Set nonValidatedAspectNames)
- * #displayString()
- * #toString(StringBuilder sb)
- */
-public abstract class AbstractNode
- extends AbstractModel
- implements Node, CallbackChangeSupport.Source
-{
-
- /** Containment hierarchy. */
- private Node parent; // pseudo-final
-
- /** Track whether the node has changed. */
- private volatile boolean dirty;
- private volatile boolean dirtyBranch;
-
- /**
- * The node's problems, as calculated during validation.
- * This list should only be modified via a ProblemSynchronizer,
- * allowing for asynchronous modification from another thread.
- */
- private Vector<Problem> problems; // pseudo-final
- private static final Object[] EMPTY_PROBLEM_MESSAGE_ARGUMENTS = new Object[0];
-
- /**
- * Cache the node's "branch" problems, as calculated during validation.
- * This list should only be modified via a ProblemSynchronizer,
- * allowing for asynchronous modification from another thread.
- * This must be recalculated every time this node or one of its
- * descendants changes it problems.
- */
- private Vector<Problem> branchProblems; // pseudo-final
-
- /** User comment. */
- private volatile String comment;
-
-
- // ********** static fields **********
-
- /**
- * Sets of transient aspect names, keyed by class.
- * This is built up lazily, as the objects are modified.
- */
- private static final HashMap<Class<? extends AbstractNode>, HashSet<String>> transientAspectNameSets = new HashMap<Class<? extends AbstractNode>, HashSet<String>>();
-
- /**
- * Sets of non-validated aspect names, keyed by class.
- * This is built up lazily, as the objects are modified.
- */
- private static final HashMap<Class<? extends AbstractNode>, HashSet<String>> nonValidatedAspectNameSets = new HashMap<Class<? extends AbstractNode>, HashSet<String>>();
-
-
- // ********** constructors **********
-
- /**
- * Most objects must have a parent.
- * Use this constructor to create a new node.
- * @see #initialize(Node)
- */
- protected AbstractNode(Node parent) {
- super();
- this.initialize();
- this.initialize(parent);
- }
-
-
- // ********** initialization **********
-
- /**
- * Initialize a newly-created instance.
- * @see #initialize(Node)
- */
- protected void initialize() {
- this.comment = ""; //$NON-NLS-1$
-
- // a new object is dirty, by definition
- this.dirty = true;
- this.dirtyBranch = true;
-
- this.problems = new Vector<Problem>();
- this.branchProblems = new Vector<Problem>();
-
- // when you override this method, don't forget to include:
- // super.initialize();
- }
-
- /**
- * Initialize a newly-created instance.
- * @see #initialize()
- */
- protected void initialize(Node parentNode) {
- this.checkParent(parentNode);
- this.parent = parentNode;
- // when you override this method, don't forget to include:
- // super.initialize(parentNode);
- }
-
- @Override
- protected ChangeSupport buildChangeSupport() {
- return new CallbackChangeSupport(this);
- }
-
-
- // ********** equality **********
-
- /**
- * Enforce object identity - do not allow objects to be equal unless
- * they are the same object.
- * Do NOT override this method - we rely on object identity extensively.
- */
- @Override
- public final boolean equals(Object o) {
- return this == o;
- }
-
- /**
- * Enforce object identity - do not allow objects to be equal unless
- * they are the same object.
- * Do NOT override this method - we rely on object identity extensively.
- */
- @Override
- public final int hashCode() {
- return super.hashCode();
- }
-
-
- // ********** containment hierarchy (parent/children) **********
-
- /**
- * INTRA-TREE API?
- * Return the node's parent in the containment hierarchy.
- * Most nodes must have a parent.
- * @see #children()
- */
- public Node getParent() {
- return this.parent;
- }
-
- /**
- * Throw an IllegalArgumentException if the parent is not valid
- * for the node.
- * By default require a non-null parent. Override if other restrictions exist
- * or the parent should be null.
- * NB: Root node model implementations will need to override this method.
- */
- protected void checkParent(Node parentNode) {
- if (parentNode == null) {
- throw new IllegalArgumentException("The parent node cannot be null");
- }
- }
-
- /**
- * INTRA-TREE API?
- * Return the node's children, which are also nodes.
- * Do NOT override this method.
- * Override #addChildrenTo(List).
- * @see #getParent()
- * @see #addChildrenTo(java.util.List)
- */
- public final Iterator<Node> children() {
- List<Node> children = new ArrayList<Node>();
- this.addChildrenTo(children);
- return children.iterator();
- }
-
- /**
- * Subclasses should override this method to add their children
- * to the specified list.
- * @see #children()
- */
- protected void addChildrenTo(List<Node> list) {
- // this class has no children, subclasses will...
- // when you override this method, don't forget to include:
- // super.addChildrenTo(list);
- }
-
- /**
- * INTRA-TREE API?
- * Return the containment hierarchy's root node.
- * Most nodes must have a root.
- * @see #getParent()
- * NB: Assume the root has no parent.
- */
- public Node root() {
- Node p = this.parent;
- return (p == null) ? this : p.root();
- }
-
- /**
- * Return whether the node is a descendant of the specified node.
- * By definition, a node is a descendant of itself.
- */
- public boolean isDescendantOf(Node node) {
- return (this == node) || this.parentIsDescendantOf(node);
- }
-
- protected boolean parentIsDescendantOf(Node node) {
- return (this.parent != null) && this.parent.isDescendantOf(node);
- }
-
- /**
- * Return a collection holding all the node's "references", and all
- * the node's descendants' "references". "References" are
- * objects that are "referenced" by another object, as opposed
- * to "owned" by another object.
- */
- public Iterator<Node.Reference> branchReferences() {
- Collection<Node.Reference> branchReferences = new ArrayList<Node.Reference>(1000); // start big
- this.addBranchReferencesTo(branchReferences);
- return branchReferences.iterator();
- }
-
- /**
- * INTRA-TREE API
- * Add the node's "references", and all the node's descendants'
- * "references", to the specified collection. "References" are
- * objects that are "referenced" by another object, as opposed
- * to "owned" by another object.
- * This method is of particular concern to Handles, since most
- * (hopefully all) "references" are held by Handles.
- * @see Reference
- * @see #children()
- */
- public void addBranchReferencesTo(Collection<Node.Reference> branchReferences) {
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.addBranchReferencesTo(branchReferences);
- }
- }
-
- /**
- * Return all the nodes in the object's branch of the tree,
- * including the node itself. The nodes will probably returned
- * in "depth-first" order.
- * Only really used for testing and debugging.
- */
- public Iterator<Node> allNodes() {
- Collection<Node> nodes = new ArrayList<Node>(1000); // start big
- this.addAllNodesTo(nodes);
- return nodes.iterator();
- }
-
- /**
- * INTRA-TREE API?
- * Add all the nodes in the object's branch of the tree,
- * including the node itself, to the specified collection.
- * Only really used for testing and debugging.
- */
- public void addAllNodesTo(Collection<Node> nodes) {
- nodes.add(this);
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.addAllNodesTo(nodes);
- }
- }
-
-
- // ********** model synchronization support **********
-
- /**
- * INTRA-TREE API
- * This is a general notification that the specified node has been
- * removed from the tree. The node receiving this notification
- * should perform any necessary updates to remain in synch
- * with the tree (e.g. clearing out or replacing any references
- * to the removed node or any of the removed node's descendants).
- * @see #isDescendantOf(Node)
- */
- public void nodeRemoved(Node node) {
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.nodeRemoved(node);
- }
- // when you override this method, don't forget to include:
- // super.nodeRemoved(node);
- }
-
- /**
- * convenience method
- * return whether node1 is a descendant of node2;
- * node1 can be null
- */
- protected boolean nodeIsDescendantOf(Node node1, Node node2) {
- return (node1 != null) && node1.isDescendantOf(node2);
- }
-
- /**
- * INTRA-TREE API
- * This is a general notification that the specified node has been
- * renamed. The node receiving this notification should mark its
- * branch dirty if necessary (i.e. it references the renamed node
- * or one of its descendants). This method is of particular concern
- * to Handles.
- * @see #isDescendantOf(Node)
- */
- public void nodeRenamed(Node node) {
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.nodeRenamed(node);
- }
- // when you override this method, don't forget to include:
- // super.nodeRenamed(node);
- }
-
-
- // ********** user comment **********
-
- /**
- * Return the object's user comment.
- */
- public final String comment() {
- return this.comment;
- }
-
- /**
- * Set the object's user comment.
- */
- public final void setComment(String comment) {
- Object old = this.comment;
- this.comment = comment;
- this.firePropertyChanged(COMMENT_PROPERTY, old, comment);
- }
-
-
- // ********** change support **********
-
- /**
- * An aspect of the node has changed:
- * - if it is a persistent aspect, mark the object dirty
- * - if it is a significant aspect, validate the object
- */
- public void aspectChanged(String aspectName) {
- if (this.aspectIsPersistent(aspectName)) {
- // System.out.println(Thread.currentThread() + " dirty change: " + this + ": " + aspectName);
- this.markDirty();
- }
- if (this.aspectChangeRequiresValidation(aspectName)) {
- // System.out.println(Thread.currentThread() + " validation change: " + this + ": " + aspectName);
- this.validate();
- }
- }
-
- protected void validate() {
- this.getValidator().validate();
- }
-
- /**
- * INTRA-TREE API
- * Return a validator that will be invoked whenever a
- * "validated" aspect of the node tree changes.
- * Typically only the root node directly holds a validator.
- * NB: Root node model implementations will need to override this method.
- */
- public Node.Validator getValidator() {
- if (this.parent == null) {
- throw new IllegalStateException("This node should not be firing change events during its construction.");
- }
- return this.parent.getValidator();
- }
-
- /**
- * Set a validator that will be invoked whenever a
- * "validated" aspect of the node tree changes.
- * Typically only the root node directly holds a validator.
- * NB: Root node model implementations will need to override this method.
- */
- public void setValidator(Node.Validator validator) {
- if (this.parent == null) {
- throw new IllegalStateException("This root node should implement #setValidator(Node.Validator).");
- }
- throw new UnsupportedOperationException("Only root nodes implement #setValidator(Node.Validator).");
- }
-
-
- // ********** dirty flag support **********
-
- /**
- * Return whether any persistent aspects of the object
- * have changed since the object was last read or saved.
- * This does NOT include changes to the object's descendants.
- */
- public final boolean isDirty() {
- return this.dirty;
- }
-
- /**
- * Return whether any persistent aspects of the object,
- * or any of its descendants, have changed since the object and
- * its descendants were last read or saved.
- */
- public final boolean isDirtyBranch() {
- return this.dirtyBranch;
- }
-
- /**
- * Return whether the object is unmodified
- * since it was last read or saved.
- * This does NOT include changes to the object's descendants.
- */
- public final boolean isClean() {
- return ! this.dirty;
- }
-
- /**
- * Return whether the object and all of its descendants
- * are unmodified since the object and
- * its descendants were last read or saved.
- */
- public final boolean isCleanBranch() {
- return ! this.dirtyBranch;
- }
-
- /**
- * Set the dirty branch flag setting. This is set to true
- * when either the object or one of its descendants becomes dirty.
- */
- private void setIsDirtyBranch(boolean dirtyBranch) {
- boolean old = this.dirtyBranch;
- this.dirtyBranch = dirtyBranch;
- this.firePropertyChanged(DIRTY_BRANCH_PROPERTY, old, dirtyBranch);
- }
-
- /**
- * Mark the object as dirty and as a dirty branch.
- * An object is marked dirty when either a "persistent" attribute
- * has changed or its save location has changed.
- */
- private void markDirty() {
- this.dirty = true;
- this.markBranchDirty();
- }
-
- /**
- * INTRA-TREE API
- * Mark the node and its parent as dirty branches.
- * This message is propagated up the containment
- * tree when a particular node becomes dirty.
- */
- public void markBranchDirty() {
- // short-circuit any unnecessary propagation
- if (this.dirtyBranch) {
- // if this is already a dirty branch, the parent must be also
- return;
- }
-
- this.setIsDirtyBranch(true);
- this.markParentBranchDirty();
- }
-
- protected void markParentBranchDirty() {
- if (this.parent != null) {
- this.parent.markBranchDirty();
- }
- }
-
- /**
- * Mark the object and all its descendants as dirty.
- * This is used when the save location of some
- * top-level object is changed and the entire
- * containment tree must be marked dirty so it
- * will be written out.
- */
- public final void markEntireBranchDirty() {
- this.markDirty();
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.markEntireBranchDirty();
- }
- }
-
- /**
- * Mark the object and all its descendants as clean.
- * Then notify the object's parent that it (the parent)
- * might now be a clean branch also.
- * Typically used when the object has just been
- * read in or written out.
- */
- public final void markEntireBranchClean() {
- this.cascadeMarkEntireBranchClean();
- this.markParentBranchCleanIfPossible();
- }
-
- protected void markParentBranchCleanIfPossible() {
- if (this.parent != null) {
- this.parent.markBranchCleanIfPossible();
- }
- }
-
- /**
- * INTRA-TREE API
- * Mark the node and all its descendants as clean.
- * Typically used when the node has just been
- * read in or written out.
- * This method is for internal use only; it is not for
- * client use.
- * Not the best of method names.... :-(
- */
- public final void cascadeMarkEntireBranchClean() {
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.cascadeMarkEntireBranchClean();
- }
- this.dirty = false;
- this.setIsDirtyBranch(false);
- }
-
- /**
- * INTRA-TREE API
- * A child node's branch has been marked clean. If the node
- * itself is clean and if all of its children are also clean, the
- * node's branch can be marked clean. Then, if the node's
- * branch is clean, the node will notify its parent that it might
- * be clean also. This message is propagated up the containment
- * tree when a particular node becomes clean.
- */
- public final void markBranchCleanIfPossible() {
- // short-circuit any unnecessary propagation
- if (this.dirty) {
- // if the object is "locally" dirty, it is still a dirty branch
- return;
- }
-
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- if (child.isDirtyBranch()) {
- return;
- }
- }
-
- this.setIsDirtyBranch(false);
- this.markParentBranchCleanIfPossible();
- }
-
- private boolean aspectIsPersistent(String aspectName) {
- return ! this.aspectIsTransient(aspectName);
- }
-
- private boolean aspectIsTransient(String aspectName) {
- return this.transientAspectNames().contains(aspectName);
- }
-
- /**
- * Return a set of the object's transient aspect names.
- * These are the aspects that, when they change, will NOT cause the
- * object to be marked dirty.
- * If you need instance-based calculation of your transient aspects,
- * override this method. If class-based calculation is sufficient,
- * override #addTransientAspectNamesTo(Set).
- */
- protected final Set<String> transientAspectNames() {
- synchronized (transientAspectNameSets) {
- HashSet<String> transientAspectNames = transientAspectNameSets.get(this.getClass());
- if (transientAspectNames == null) {
- transientAspectNames = new HashSet<String>();
- this.addTransientAspectNamesTo(transientAspectNames);
- transientAspectNameSets.put(this.getClass(), transientAspectNames);
- }
- return transientAspectNames;
- }
- }
-
- /**
- * Add the object's transient aspect names to the specified set.
- * These are the aspects that, when they change, will NOT cause the
- * object to be marked dirty.
- * If class-based calculation of your transient aspects is sufficient,
- * override this method. If you need instance-based calculation,
- * override #transientAspectNames().
- */
- protected void addTransientAspectNamesTo(Set<String> transientAspectNames) {
- transientAspectNames.add(DIRTY_BRANCH_PROPERTY);
- transientAspectNames.add(BRANCH_PROBLEMS_LIST);
- transientAspectNames.add(HAS_BRANCH_PROBLEMS_PROPERTY);
- // when you override this method, don't forget to include:
- // super.addTransientAspectNamesTo(transientAspectNames);
- }
-
- /**
- * Return the dirty nodes in the object's branch of the tree,
- * including the node itself (if appropriate).
- * Only really used for testing and debugging.
- */
- public final Iterator<Node> allDirtyNodes() {
- return new FilteringIterator<Node, Node>(this.allNodes()) {
- @Override
- protected boolean accept(Node node) {
- return (node instanceof AbstractNode) && ((AbstractNode) node).isDirty();
- }
- };
- }
-
-
- // ********** problems **********
-
- /**
- * Return the node's problems.
- * This does NOT include the problems of the node's descendants.
- * @see #branchProblems()
- */
- public final Iterator<Problem> problems() {
- return new CloneIterator<Problem>(this.problems); // removes are not allowed
- }
-
- /**
- * Return the size of the node's problems.
- * This does NOT include the problems of the node's descendants.
- * @see #branchProblemsSize()
- */
- public final int problemsSize() {
- return this.problems.size();
- }
-
- /**
- * Return whether the node has problems
- * This does NOT include the problems of the node's descendants.
- * @see #hasBranchProblems()
- */
- public final boolean hasProblems() {
- return ! this.problems.isEmpty();
- }
-
- /**
- * Return all the node's problems along with all the
- * node's descendants' problems.
- */
- public final ListIterator<Problem> branchProblems() {
- return new CloneListIterator<Problem>(this.branchProblems); // removes are not allowed
- }
-
- /**
- * Return the size of all the node's problems along with all the
- * node's descendants' problems.
- */
- public final int branchProblemsSize() {
- return this.branchProblems.size();
- }
-
- /**
- * Return whether the node or any of its descendants have problems.
- */
- public final boolean hasBranchProblems() {
- return ! this.branchProblems.isEmpty();
- }
-
- public final boolean containsBranchProblem(Problem problem) {
- return this.branchProblems.contains(problem);
- }
-
- protected final Problem buildProblem(String messageKey, Object... messageArguments) {
- return new DefaultProblem(this, messageKey, messageArguments);
- }
-
- protected final Problem buildProblem(String messageKey) {
- return this.buildProblem(messageKey, EMPTY_PROBLEM_MESSAGE_ARGUMENTS);
- }
-
- /**
- * Validate the node and all of its descendants,
- * and update their sets of "branch" problems.
- * If the node's "branch" problems have changed,
- * notify the node's parent.
- */
- public void validateBranch() {
- if (this.validateBranchInternal()) {
- // if our "branch" problems have changed, then
- // our parent must rebuild its "branch" problems also
- this.rebuildParentBranchProblems();
- }
- }
-
- protected void rebuildParentBranchProblems() {
- if (this.parent != null) {
- this.parent.rebuildBranchProblems();
- }
- }
-
- /**
- * INTRA-TREE API
- * Validate the node and all of its descendants,
- * and update their sets of "branch" problems.
- * Return true if the collection of "branch" problems has changed.
- * This method is for internal use only; it is not for
- * client use.
- */
- public boolean validateBranchInternal() {
- // rebuild "branch" problems in children first
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- // ignore the return value because we are going to rebuild our "branch"
- // problems no matter what, to see if they have changed
- child.validateBranchInternal();
- }
-
- this.problems.clear();
- this.addProblemsTo(this.problems);
-
- return this.checkBranchProblems();
- }
-
- /**
- * Check for any problems and add them to the specified list.
- * This method should ONLY add problems for this particular node;
- * it should NOT add problems for any of this node's descendants
- * or ancestors. (Although there will be times when it is debatable
- * as to which node a problem "belongs" to....)
- *
- * NB: This method should NOT modify ANY part of the node's state!
- * It is a READ-ONLY behavior. ONLY the list of current problems
- * passed in to the method should be modified.
- */
- protected void addProblemsTo(List<Problem> currentProblems) {
- // The default is to do nothing.
- // When you override this method, don't forget to include:
- // super.addProblemsTo(currentProblems);
- }
-
- /**
- * Rebuild the "branch" problems and return whether they have
- * changed.
- * NB: The entire collection of "branch" problems must be re-calculated
- * with EVERY "significant" change - we cannot keep it in synch via
- * change notifications because if a descendant with problems is
- * removed or replaced we will not receive notification that its
- * problems were removed from our "branch" problems.
- */
- private boolean checkBranchProblems() {
- Vector<Problem> oldBranchProblems = new Vector<Problem>(this.branchProblems);
- int oldSize = this.branchProblems.size();
-
- this.branchProblems.clear();
- this.branchProblems.addAll(this.problems);
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- child.addBranchProblemsTo(this.branchProblems);
- }
-
- // if the size has changed to or from zero, our virtual flag has changed
- int newSize = this.branchProblems.size();
- if ((oldSize == 0) && (newSize != 0)) {
- this.firePropertyChanged(HAS_BRANCH_PROBLEMS_PROPERTY, false, true);
- } else if ((oldSize != 0) && (newSize == 0)) {
- this.firePropertyChanged(HAS_BRANCH_PROBLEMS_PROPERTY, true, false);
- }
-
- if (oldBranchProblems.equals(this.branchProblems)) {
- return false; // our "branch" problems did not change
- }
- // our "branch" problems changed
- this.fireListChanged(BRANCH_PROBLEMS_LIST);
- return true;
- }
-
- /**
- * INTRA-TREE API
- * Add all the problems of the node and all
- * the problems of its descendants to the
- * specified collection.
- */
- public final void addBranchProblemsTo(List<Problem> list) {
- list.addAll(this.branchProblems);
- }
-
- /**
- * INTRA-TREE API
- * A child node's "branch" problems changed;
- * therefore the node's "branch" problems have changed also and
- * must be rebuilt.
- */
- public final void rebuildBranchProblems() {
- if ( ! this.checkBranchProblems()) {
- throw new IllegalStateException("we should not get here unless our \"branch\" problems have changed");
- }
- this.rebuildParentBranchProblems();
- }
-
- /**
- * Clear the node's "branch" problems and the "branch"
- * problems of all of its descendants.
- * If the node's "branch" problems have changed,
- * notify the node's parent.
- */
- public final void clearAllBranchProblems() {
- if (this.clearAllBranchProblemsInternal()) {
- // if our "branch" problems have changed, then
- // our parent must rebuild its "branch" problems also
- this.rebuildParentBranchProblems();
- }
- }
-
- /**
- * INTRA-TREE API
- * Clear the node's "branch" problems and the "branch"
- * problems of all of its descendants.
- * Return true if the collection of "branch" problems has changed.
- * This method is for internal use only; it is not for
- * client use.
- */
- public final boolean clearAllBranchProblemsInternal() {
- if (this.branchProblems.isEmpty()) {
- return false;
- }
- for (Iterator<Node> stream = this.children(); stream.hasNext(); ) {
- Node child = stream.next(); // pull out the child to ease debugging
- // ignore the return value because we are going to clear our "branch"
- // problems no matter what
- child.clearAllBranchProblemsInternal();
- }
- this.problems.clear();
- this.branchProblems.clear();
- this.firePropertyChanged(HAS_BRANCH_PROBLEMS_PROPERTY, true, false);
- this.fireListChanged(BRANCH_PROBLEMS_LIST);
- return true;
- }
-
- /**
- * Return whether a change to specified aspect requires a re-validation
- * of the node's tree.
- */
- private boolean aspectChangeRequiresValidation(String aspectName) {
- return ! this.aspectChangeDoesNotRequireValidation(aspectName);
- }
-
- private boolean aspectChangeDoesNotRequireValidation(String aspectName) {
- return this.nonValidatedAspectNames().contains(aspectName);
- }
-
- /**
- * Return a set of the object's "non-validated" aspect names.
- * These are the aspects that, when they change, will NOT cause the
- * object (or its containing tree) to be validated, i.e. checked for problems.
- * If you need instance-based calculation of your "non-validated" aspects,
- * override this method. If class-based calculation is sufficient,
- * override #addNonValidatedAspectNamesTo(Set).
- */
- protected final Set<String> nonValidatedAspectNames() {
- synchronized (nonValidatedAspectNameSets) {
- HashSet<String> nonValidatedAspectNames = nonValidatedAspectNameSets.get(this.getClass());
- if (nonValidatedAspectNames == null) {
- nonValidatedAspectNames = new HashSet<String>();
- this.addNonValidatedAspectNamesTo(nonValidatedAspectNames);
- nonValidatedAspectNameSets.put(this.getClass(), nonValidatedAspectNames);
- }
- return nonValidatedAspectNames;
- }
- }
-
- /**
- * Add the object's "non-validated" aspect names to the specified set.
- * These are the aspects that, when they change, will NOT cause the
- * object (or its containing tree) to be validated, i.e. checked for problems.
- * If class-based calculation of your "non-validated" aspects is sufficient,
- * override this method. If you need instance-based calculation,
- * override #nonValidatedAspectNames().
- */
- protected void addNonValidatedAspectNamesTo(Set<String> nonValidatedAspectNames) {
- nonValidatedAspectNames.add(COMMENT_PROPERTY);
- nonValidatedAspectNames.add(DIRTY_BRANCH_PROPERTY);
- nonValidatedAspectNames.add(BRANCH_PROBLEMS_LIST);
- nonValidatedAspectNames.add(HAS_BRANCH_PROBLEMS_PROPERTY);
- // when you override this method, don't forget to include:
- // super.addNonValidatedAspectNamesTo(nonValidatedAspectNames);
- }
-
-
- // ********** display methods **********
-
- /**
- * Compare display strings.
- */
- public int compareTo(Node node) {
- return DEFAULT_COMPARATOR.compare(this, node);
- }
-
- /**
- * Return a developer-friendly String. If you want something useful for
- * displaying in a user interface, use #displayString().
- * If you want to give more information in your #toString(),
- * override #toString(StringBuilder sb).
- * Whatever you add to that string buffer will show up between the parentheses.
- * @see AbstractModel#toString(StringBuilder sb)
- * @see #displayString()
- */
- @Override
- public final String toString() {
- return super.toString();
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AsynchronousValidator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AsynchronousValidator.java
deleted file mode 100644
index fd2059cc8c..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/AsynchronousValidator.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.SynchronizedBoolean;
-
-/**
- * This implementation of the PluggableValidator.Delegate interface
- * simply sets a shared "validate" flag to true. This should trigger a
- * separate "validation" thread to begin validating the appropriate
- * branch of nodes.
- */
-public class AsynchronousValidator
- implements PluggableValidator.Delegate
-{
- private SynchronizedBoolean validateFlag;
-
- /**
- * Construct a validator delegate with the specified shared
- * "validate" flag. This flag should be shared with
- * another thread that will perform the actual validation.
- */
- public AsynchronousValidator(SynchronizedBoolean validateFlag) {
- super();
- this.validateFlag = validateFlag;
- }
-
- /**
- * Set the shared "validate" flag to true, triggering
- * an asynchronous validation of the appropriate
- * branch of nodes.
- */
- public void validate() {
- this.validateFlag.setTrue();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.validateFlag);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/DefaultProblem.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/DefaultProblem.java
deleted file mode 100644
index 9d3898c59d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/DefaultProblem.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import java.util.Arrays;
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * This class is a straightforward implementation of the Problem interface.
- */
-public class DefaultProblem
- implements Problem
-{
- private final Node source;
- private final String messageKey;
- private final Object[] messageArguments;
-
-
- DefaultProblem(Node source, String messageKey, Object[] messageArguments) {
- super();
- this.source = source;
- this.messageKey = messageKey;
- this.messageArguments = messageArguments;
- }
-
-
- // ********** Problem implementation **********
-
- public Node source() {
- return this.source;
- }
-
- public String messageKey() {
- return this.messageKey;
- }
-
- public Object[] messageArguments() {
- return this.messageArguments;
- }
-
-
- // ********** Object overrides **********
-
- /**
- * We implement #equals(Object) because problems are repeatedly
- * re-calculated and the resulting problems merged with the existing
- * set of problems; and we want to keep the original problems and
- * ignore any freshly-generated duplicates.
- * Also, problems are not saved to disk....
- */
- @Override
- public boolean equals(Object o) {
- if ( ! (o instanceof Problem)) {
- return false;
- }
- Problem other = (Problem) o;
- return this.source == other.source()
- && this.messageKey.equals(other.messageKey())
- && Arrays.equals(this.messageArguments, other.messageArguments());
- }
-
- @Override
- public int hashCode() {
- return this.source.hashCode() ^ this.messageKey.hashCode();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.messageKey);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Node.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Node.java
deleted file mode 100644
index 2936883fce..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Node.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import java.text.Collator;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * This interface defines the methods that must be implemented
- * by any class whose instances are to be part of a containment hierarchy
- * that supports a "dirty" state and validation "problems".
- *
- * Note: Methods marked "INTRA-TREE API" are typically only used by
- * the nodes themselves, as opposed to clients of the nodes. These
- * methods are called by a node on either its parent or its children.
- */
-public interface Node extends Model, Comparable<Node> {
-
-
- // ********** containment hierarchy (parent/children) **********
-
- /**
- * INTRA-TREE API?
- * Return the node's parent in the containment hierarchy.
- * Most nodes must have a parent. The parent is immutable.
- * @see #children()
- */
- Node getParent();
-
- /**
- * INTRA-TREE API?
- * Return the node's children, which are also nodes.
- * @see #getParent()
- */
- Iterator<Node> children();
-
- /**
- * INTRA-TREE API?
- * Return the containment hierarchy's root node.
- * Most nodes must have a root.
- * @see #getParent()
- */
- Node root();
-
- /**
- * Return whether the node is a descendant of the specified node.
- * By definition, a node is a descendant of itself.
- */
- boolean isDescendantOf(Node node);
-
- /**
- * INTRA-TREE API
- * Add the node's "references", and all the node's descendants'
- * "references", to the specified collection. "References" are
- * objects that are "referenced" by another object, as opposed
- * to "owned" by another object.
- * This method is of particular concern to Handles, since most
- * (hopefully all) "references" are held by Handles.
- * @see Reference
- * @see #children()
- */
- void addBranchReferencesTo(Collection<Node.Reference> branchReferences);
-
- /**
- * INTRA-TREE API?
- * Add all the nodes in the object's branch of the tree,
- * including the node itself, to the specified collection.
- * Only really used for testing and debugging.
- */
- void addAllNodesTo(Collection<Node> nodes);
-
-
- // ********** model synchronization support **********
-
- /**
- * INTRA-TREE API
- * This is a general notification that the specified node has been
- * removed from the tree. The node receiving this notification
- * should perform any necessary updates to remain in synch
- * with the tree (e.g. clearing out or replacing any references
- * to the removed node or any of the removed node's descendants).
- * @see #isDescendantOf(Node)
- */
- void nodeRemoved(Node node);
-
- /**
- * INTRA-TREE API
- * This is a general notification that the specified node has been
- * renamed. The node receiving this notification should mark its
- * branch dirty if necessary (i.e. it references the renamed node
- * or one of its descendants). This method is of particular concern
- * to Handles.
- * @see #isDescendantOf(Node)
- */
- void nodeRenamed(Node node);
-
-
- // ********** dirty flag support **********
-
- /**
- * Return whether any persistent aspects of the node,
- * or any of its descendants, have changed since the node and
- * its descendants were last read or saved.
- */
- boolean isDirtyBranch();
- String DIRTY_BRANCH_PROPERTY = "dirtyBranch";
-
- /**
- * INTRA-TREE API
- * Mark the node and its parent as dirty branches.
- * This message is propagated up the containment
- * tree when a particular node becomes dirty.
- */
- void markBranchDirty();
-
- /**
- * Mark the node and all its descendants as dirty.
- * This is used when the save location of some
- * top-level node is changed and the entire
- * containment tree must be marked dirty so it
- * will be written out.
- */
- void markEntireBranchDirty();
-
- /**
- * INTRA-TREE API
- * A child node's branch has been marked clean. If the node
- * itself is clean and if all of its children are also clean, the
- * node's branch can be marked clean. Then, if the node's
- * branch is clean, the node will notify its parent that it might
- * be clean also. This message is propagated up the containment
- * tree when a particular node becomes clean.
- */
- void markBranchCleanIfPossible();
-
- /**
- * INTRA-TREE API
- * Mark the node and all its descendants as clean.
- * Typically used when the node has just been
- * read in or written out.
- * This method is for internal use only; it is not for
- * client use.
- * Not the best of method names.... :-(
- */
- void cascadeMarkEntireBranchClean();
-
-
- // ********** problems **********
-
- /**
- * INTRA-TREE API
- * Return a validator that will be invoked whenever a
- * "validated" aspect of the node tree changes.
- * Typically only the root node directly holds a validator.
- */
- Validator getValidator();
-
- /**
- * Set a validator that will be invoked whenever a
- * "validated" aspect of the node tree changes.
- * Typically only the root node directly holds a validator.
- */
- void setValidator(Validator validator);
-
- /**
- * Validate the node and its descendants.
- * This is an explicit request invoked by a client; and it will
- * typically be followed by a call to one of the following methods:
- * #branchProblems()
- * #hasBranchProblems()
- * Whether the node maintains its problems on the fly
- * or waits until this method is called is determined by the
- * implementation.
- * @see Problem
- */
- void validateBranch();
-
- /**
- * INTRA-TREE API
- * Validate the node and all of its descendants,
- * and update their sets of "branch" problems.
- * Return true if the collection of "branch" problems has changed.
- * This method is for internal use only; it is not for
- * client use.
- */
- boolean validateBranchInternal();
-
- /**
- * Return all the node's problems along with all the
- * node's descendants' problems.
- */
- ListIterator<Problem> branchProblems();
- String BRANCH_PROBLEMS_LIST = "branchProblems";
-
- /**
- * Return the size of all the node's problems along with all the
- * node's descendants' problems.
- */
- int branchProblemsSize();
-
- /**
- * Return whether the node or any of its descendants have problems.
- */
- boolean hasBranchProblems();
- String HAS_BRANCH_PROBLEMS_PROPERTY = "hasBranchProblems";
-
- /**
- * Return whether the node contains the specified branch problem.
- */
- boolean containsBranchProblem(Problem problem);
-
- /**
- * INTRA-TREE API
- * Something changed, rebuild the node's collection of branch problems.
- */
- void rebuildBranchProblems();
-
- /**
- * INTRA-TREE API
- * Add the node's problems, and all the node's descendants'
- * problems, to the specified list.
- * A call to this method should be immediately preceded by a call to
- * #validateBranch() or all of the problems might not be
- * added to the list.
- * @see Problem
- */
- void addBranchProblemsTo(List<Problem> branchProblems);
-
- /**
- * Clear the node's "branch" problems and the "branch"
- * problems of all of its descendants.
- */
- void clearAllBranchProblems();
-
- /**
- * INTRA-TREE API
- * Clear the node's "branch" problems and the "branch"
- * problems of all of its descendants.
- * Return true if the collection of "branch" problems has changed.
- * This method is for internal use only; it is not for
- * client use.
- */
- boolean clearAllBranchProblemsInternal();
-
-
- // ********** comment **********
-
- /**
- * Return the user comment concerning the node.
- */
- String comment();
- String COMMENT_PROPERTY = "comment";
-
- /**
- * Set the user comment concerning the node.
- */
- void setComment(String comment);
-
-
- // ********** displaying/sorting **********
-
- /**
- * Return a string representation of the model, suitable for sorting.
- */
- String displayString();
-
-
- // ********** sub-interfaces **********
-
- /**
- * Simple interface defining a "reference" between two nodes.
- * @see Node#addBranchReferencesTo(java.util.Collection)
- */
- interface Reference {
-
- /**
- * Return the "source" node of the reference, i.e. the node that
- * references the "target" node.
- */
- Node source();
-
- /**
- * Return the "target" node of the reference, i.e. the node that
- * is referenced by the "source" node.
- */
- Node target();
-
- }
-
-
- /**
- * A validator will validate a node as appropriate.
- * Typically the validation will
- * - occur whenever a node has changed
- * - encompass the entire tree containing the node
- * - execute asynchronously
- */
- interface Validator {
-
- /**
- * A "significant" aspect has changed;
- * validate the node as appropriate
- */
- void validate();
-
- /**
- * Stop all validation of the node until #resume() is called.
- * This can be used to improve the performance of any long-running
- * action that triggers numerous changes to the node. Be sure to
- * match a call to this method with a corresponding call to
- * #resume().
- */
- void pause();
-
- /**
- * Resume validation of the node. This method can only be
- * called after a matching call to #pause().
- */
- void resume();
-
- }
-
-
- // ********** helper implementations **********
-
- /**
- * Straightforward implementation of the Reference interface
- * defined above.
- */
- public class SimpleReference implements Reference {
- private Node source;
- private Node target;
- public SimpleReference(Node source, Node target) {
- super();
- if (source == null || target == null) {
- throw new NullPointerException();
- }
- this.source = source;
- this.target = target;
- }
- public Node source() {
- return this.source;
- }
- public Node target() {
- return this.target;
- }
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.source + " => " + this.target);
- }
- }
-
- /**
- * Typical comparator that can be used to sort a collection of nodes.
- * Sort based on display string:
- * - identical objects are equal (which means that cannot
- * co-exist in a SortedSet)
- * - use the default collator (which typically interleaves
- * lower- and upper-case letters)
- * - allow duplicate display strings (from different objects)
- * - try to return consistent results for same object pairs
- */
- Comparator<Node> DEFAULT_COMPARATOR =
- new Comparator<Node>() {
- public int compare(Node node1, Node node2) {
- // disallow duplicates based on object identity
- if (node1 == node2) {
- return 0;
- }
-
- // first compare display strings using the default collator
- int result = Collator.getInstance().compare(node1.displayString(), node2.displayString());
- if (result != 0) {
- return result;
- }
-
- // then compare using object-id
- result = System.identityHashCode(node1) - System.identityHashCode(node2);
- if (result != 0) {
- return result;
- }
-
- // It's unlikely that we get to this point; but, just in case, we will return -1.
- // Unfortunately, this introduces some mild unpredictability to the sort order
- // (unless the objects are always passed into this method in the same order).
- return -1; // if all else fails, indicate that o1 < o2
- }
- @Override
- public String toString() {
- return "Node.DEFAULT_COMPARATOR";
- }
- };
-
-
- /**
- * This validator does nothing to validate the node.
- */
- Validator NULL_VALIDATOR =
- new PluggableValidator(PluggableValidator.Delegate.Null.instance()) {
- @Override
- public String toString() {
- return "Node.NULL_VALIDATOR";
- }
- };
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java
deleted file mode 100644
index c44f8aab43..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/PluggableValidator.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.SynchronizedBoolean;
-
-/**
- * This implementation of the Validator interface implements the
- * pause/resume portion of the protocol, but delegates the actual
- * validation to a "pluggable" delegate.
- */
-public class PluggableValidator
- implements Node.Validator
-{
- private boolean pause;
- private boolean validateOnResume;
- private final Delegate delegate;
-
-
- /**
- * Convenience factory method.
- */
- public static Node.Validator buildAsynchronousValidator(SynchronizedBoolean validateFlag) {
- return new PluggableValidator(new AsynchronousValidator(validateFlag));
- }
-
- /**
- * Convenience factory method.
- */
- public static Node.Validator buildSynchronousValidator(Node node) {
- return new PluggableValidator(new SynchronousValidator(node));
- }
-
- /**
- * Construct a validator with the specified delegate.
- */
- public PluggableValidator(Delegate delegate) {
- super();
- this.pause = false;
- this.validateOnResume = false;
- this.delegate = delegate;
- }
-
- public synchronized void validate() {
- if (this.pause) {
- this.validateOnResume = true;
- } else {
- this.delegate.validate();
- }
- }
-
- public synchronized void pause() {
- if (this.pause) {
- throw new IllegalStateException("already paused");
- }
- this.pause = true;
- }
-
- public synchronized void resume() {
- if ( ! this.pause) {
- throw new IllegalStateException("not paused");
- }
- this.pause = false;
- // validate any changes that occurred while the validation was paused
- if (this.validateOnResume) {
- this.validateOnResume = false;
- this.delegate.validate();
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.delegate);
- }
-
-
- // ********** member interface **********
-
- /**
- * Interface implemented by any delegates of a pluggable validator.
- */
- public interface Delegate {
-
- /**
- * The validator is not "paused" - perform the appropriate validation.
- */
- void validate();
-
-
- /**
- * This delegate does nothing.
- */
- final class Null implements Delegate {
- public static final Delegate INSTANCE = new Null();
- public static Delegate instance() {
- return INSTANCE;
- }
- // ensure single instance
- private Null() {
- super();
- }
- public void validate() {
- // do nothing
- }
- @Override
- public String toString() {
- return "PluggableValidator.Delegate.Null";
- }
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Problem.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Problem.java
deleted file mode 100644
index 4f8e730362..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/Problem.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-/**
- * Define an interface describing the problems associated with a node.
- */
-public interface Problem {
-
- /**
- * Return the node most closely associated with the problem.
- */
- Node source();
-
- /**
- * Return a key that can be used to uniquely identify the problem's message.
- */
- String messageKey();
-
- /**
- * Return the arguments associate with the problem's message.
- */
- Object[] messageArguments();
-
- /**
- * Return whether the problem is equal to the specified object.
- * It is equal if the specified object is a implementation of the
- * Problem interface and its source, message key, and message
- * arguments are all equal to this problem's.
- */
- boolean equals(Object o);
-
- /**
- * Return the problem's hash code, which should calculated as an
- * XOR of the source's hash code and the message key's hash code.
- */
- int hashCode();
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/RunnableValidation.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/RunnableValidation.java
deleted file mode 100644
index 367d57a028..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/RunnableValidation.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import org.eclipse.jpt.utility.internal.SynchronizedBoolean;
-
-/**
- * This implementation of Runnable will asynchronously validate
- * a branch of nodes. It will wait until a shared "validate" flag is
- * set to validate the branch. Once the the branch is validated,
- * the thread will quiesce until the flag is set again.
- *
- * There are two ways to stop this thread:
- * - Thread.interrupt()
- * - set the "continue" flag to false
- * For now, these two are equivalent; but in the future we might
- * pass the "continue" flag to the Node.validateBranch()
- * method so we can short-circuit the validation instead of waiting
- * until the entire branch is validated.
- */
-public class RunnableValidation
- implements Runnable
-{
- /** The node whose branch this thread will validate. */
- private final Node node;
-
- /** When this flag is set to true, we kick off the validation routine. */
- private final SynchronizedBoolean validateFlag;
-
- /** When this flag is set to false, we allow this thread to die. */
- private final SynchronizedBoolean continueFlag;
-
- /** Log any exceptions encountered during validation with the following settings. */
- private final Logger exceptionLogger;
- private final Level exceptionLevel;
- private final String exceptionMessage;
-
-
- /**
- * Construct a validation thread.
- */
- public RunnableValidation(
- Node node,
- SynchronizedBoolean validateFlag,
- SynchronizedBoolean continueFlag,
- Logger exceptionLogger,
- Level exceptionLevel,
- String exceptionMessage
- ) {
- super();
- this.node = node;
- this.validateFlag = validateFlag;
- this.continueFlag = continueFlag;
- this.exceptionLogger = exceptionLogger;
- this.exceptionLevel = exceptionLevel;
- this.exceptionMessage = exceptionMessage;
- }
-
-
- // ********** Runnable Implementation **********
-
- /**
- * Loop while the "continue" flag is true and the thread
- * has not been interrupted by another thread.
- * In each loop: Wait until the "validate" flag is set to true,
- * then set it back to false and validate the branch of nodes.
- */
- public void run() {
- while (this.continueFlag.isTrue()) {
- try {
- this.validateFlag.waitToSetFalse();
- } catch (InterruptedException ex) {
- // we were interrupted while waiting, must be quittin' time
- return;
- }
- this.validateNode();
- }
- }
-
- /**
- * Validate the node, logging any exceptions.
- * If an exception occurs, we terminate the validation until the
- * "validation" flag is set again. Some exceptions occur because
- * of concurrent changes to the model that occur *after* validation
- * starts but before it completes an entire pass over the model. If that
- * is the case, things should be OK; because the exception will be
- * caught and the "validation" flag will have been set again *during* the
- * initial validation pass. So when we return from catching the exception
- * we will simply re-start the validation, hopefully with the model in
- * a consistent state that will prevent another exception from
- * occurring. Of course, if we have any exceptions that are *not*
- * the result of the model being in an inconsistent state, we will
- * probably fill the log; and those exceptions are bugs that need
- * to be fixed. (!) Hopefully the user will notice the enormous log and
- * contact support.... ~bjv
- */
- private void validateNode() {
- try {
- this.node.validateBranch();
- } catch (Throwable ex) {
- this.logException(ex);
- }
- }
-
- /**
- * We need to do all this because Logger#log(LogRecord) does not pass through
- * Logger#doLog(LogRecord) like all the other Logger#log(...) methods.
- */
- private void logException(Throwable ex) {
- LogRecord logRecord = new LogRecord(this.exceptionLevel, this.exceptionMessage);
- logRecord.setParameters(new Object[] { this.node.displayString() });
- logRecord.setThrown(ex);
- logRecord.setLoggerName(this.exceptionLogger.getName());
- logRecord.setResourceBundle(this.exceptionLogger.getResourceBundle());
- this.exceptionLogger.log(logRecord);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/SynchronousValidator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/SynchronousValidator.java
deleted file mode 100644
index ede6b8b8f0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/node/SynchronousValidator.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.node;
-
-import org.eclipse.jpt.utility.internal.StringTools;
-
-/**
- * This implementation of the PluggableValidator.Delegate interface
- * will validate the node immediately.
- *
- * This is useful for debugging in a single thread or generating
- * problem reports.
- */
-public class SynchronousValidator
- implements PluggableValidator.Delegate
-{
- private final Node node;
-
- /**
- * Construct a validator that will immediately validate the
- * specified node.
- */
- public SynchronousValidator(Node node) {
- super();
- this.node = node;
- }
-
- public void validate() {
- this.node.validateBranch();
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.node);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CachingComboBoxModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CachingComboBoxModel.java
deleted file mode 100644
index 8ebe2617e6..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CachingComboBoxModel.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import javax.swing.ComboBoxModel;
-
-/**
- * This interface allows a client to better control the performance of
- * a combo box model by allowing the client to specify when it is
- * acceptable for the model to "cache" and "uncache" its list of elements.
- * The model may ignore these hints if appropriate.
- */
-public interface CachingComboBoxModel extends ComboBoxModel {
-
- /**
- * Cache the comboBoxModel List. If you call this, you
- * must make sure to call uncacheList() as well. Otherwise
- * stale data will be in the ComboBox until cacheList() is
- * called again or uncacheList() is called.
- */
- void cacheList();
-
- /**
- * Clear the cached list. Next time the list is needed it will
- * be built when it is not cached.
- */
- void uncacheList();
-
- /**
- * Check to see if the list is already cached. This can be used for
- * MouseEvents, since they are not terribly predictable.
- */
- boolean isCached();
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java
deleted file mode 100644
index 45ec6be9e2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/CheckBoxTableCellRenderer.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.JCheckBox;
-import javax.swing.JTable;
-import javax.swing.SwingConstants;
-import javax.swing.UIManager;
-import javax.swing.border.Border;
-import org.eclipse.jpt.utility.internal.swing.TableCellEditorAdapter.ImmediateEditListener;
-
-/**
- * Make the cell look like a check box.
- */
-public class CheckBoxTableCellRenderer implements TableCellEditorAdapter.Renderer {
-
- /** the component used to paint the cell */
- private final JCheckBox checkBox;
-
- /** the listener to be notified on an immediate edit */
- protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
-
- /** "normal" border - assume the default table "focus" border is 1 pixel thick */
- private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a cell renderer with no label or icon.
- */
- public CheckBoxTableCellRenderer() {
- super();
- this.checkBox = this.buildCheckBox();
- // by default, check boxes do not paint their borders
- this.checkBox.setBorderPainted(true);
- // this setting is recommended for check boxes inside of trees and tables
- this.checkBox.setBorderPaintedFlat(true);
- }
-
- /**
- * Construct a cell renderer with the specified text and icon,
- * either of which may be null.
- */
- public CheckBoxTableCellRenderer(String text, Icon icon) {
- this();
- this.setText(text);
- this.setIcon(icon);
- }
-
- /**
- * Construct a cell renderer with the specified text.
- */
- public CheckBoxTableCellRenderer(String text) {
- this(text, null);
- }
-
- /**
- * Construct a cell renderer with the specified icon.
- */
- public CheckBoxTableCellRenderer(Icon icon) {
- this(null, icon);
- }
-
- protected JCheckBox buildCheckBox() {
- JCheckBox cb = new JCheckBox();
- cb.addActionListener(this.buildActionListener());
- return cb;
- }
-
- private ActionListener buildActionListener() {
- return new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (CheckBoxTableCellRenderer.this.immediateEditListener != null) {
- CheckBoxTableCellRenderer.this.immediateEditListener.immediateEdit();
- }
- }
- };
- }
-
-
- // ********** TableCellRenderer implementation **********
-
- public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- this.checkBox.setHorizontalAlignment(SwingConstants.CENTER);
- this.checkBox.setComponentOrientation(table.getComponentOrientation());
- this.checkBox.setFont(table.getFont());
- this.checkBox.setEnabled(table.isEnabled());
-
- this.checkBox.setForeground(this.foregroundColor(table, value, selected, hasFocus, row, column));
- this.checkBox.setBackground(this.backgroundColor(table, value, selected, hasFocus, row, column));
- // once the colors are set, calculate opaque setting
- this.checkBox.setOpaque(this.cellIsOpaqueIn(table, value, selected, hasFocus, row, column));
- this.checkBox.setBorder(this.border(table, value, selected, hasFocus, row, column));
-
- this.setValue(value);
- return this.checkBox;
- }
-
- /**
- * Return the cell's foreground color.
- */
- protected Color foregroundColor(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- if (selected) {
- if (hasFocus && table.isCellEditable(row, column)) {
- return UIManager.getColor("Table.focusCellForeground");
- }
- return table.getSelectionForeground();
- }
- return table.getForeground();
- }
-
- /**
- * Return the cell's background color.
- */
- protected Color backgroundColor(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- if (selected) {
- if (hasFocus && table.isCellEditable(row, column)) {
- return UIManager.getColor("Table.focusCellBackground");
- }
- return table.getSelectionBackground();
- }
- return table.getBackground();
- }
-
- /**
- * Return the cell's border.
- */
- protected Border border(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- return hasFocus ? UIManager.getBorder("Table.focusCellHighlightBorder") : NO_FOCUS_BORDER;
- }
-
- /**
- * Return whether the cell should be opaque in the table.
- * If the cell's background is the same as the table's background
- * and table is opaque, we don't need to paint the background -
- * the table will do it.
- */
- protected boolean cellIsOpaqueIn(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- Color cellBackground = this.checkBox.getBackground();
- Color tableBackground = table.getBackground();
- return ! (table.isOpaque() && cellBackground.equals(tableBackground));
- }
-
- /**
- * Set the check box's value.
- */
- protected void setValue(Object value) {
- // CR#3999318 - This null check needs to be removed once JDK bug is fixed
- if (value == null) {
- value = Boolean.FALSE;
- }
- this.checkBox.setSelected(((Boolean) value).booleanValue());
- }
-
-
- // ********** TableCellEditorAdapter.Renderer implementation **********
-
- public Object getValue() {
- return Boolean.valueOf(this.checkBox.isSelected());
- }
-
- public void setImmediateEditListener(ImmediateEditListener listener) {
- this.immediateEditListener = listener;
- }
-
- // ********** public API **********
-
- /**
- * Set the check box's text; which by default is blank.
- */
- public void setText(String text) {
- this.checkBox.setText(text);
- }
-
- /**
- * Set the check box's icon; which by default is not present.
- */
- public void setIcon(Icon icon) {
- this.checkBox.setIcon(icon);
- }
-
- /**
- * Return the renderer's preferred height. This allows you
- * to set the table's row height to something the check box
- * will look good in....
- */
- public int preferredHeight() {
- // add in space for the border top and bottom
- return (int) this.checkBox.getPreferredSize().getHeight() + 2;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java
deleted file mode 100644
index 55d8d1f9a0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ComboBoxTableCellRenderer.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Graphics;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import javax.swing.BorderFactory;
-import javax.swing.ComboBoxModel;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JTable;
-import javax.swing.ListCellRenderer;
-import javax.swing.SwingConstants;
-import javax.swing.UIManager;
-import javax.swing.border.Border;
-import javax.swing.event.PopupMenuEvent;
-import javax.swing.event.PopupMenuListener;
-import org.eclipse.jpt.utility.internal.ClassTools;
-
-/**
- * Make the cell look like a combo-box.
- */
-public class ComboBoxTableCellRenderer implements TableCellEditorAdapter.Renderer {
-
- /* caching the combo box because we are caching the comboBoxModel.
- * Everytime we rebuilt the comboBox we would set the model on it and not
- * remove the model from the old combo box. This meant that new listeners
- * kept being added to the comboBoxModel for every comboBox build.
- * Not sure if there is a way to clear out the old combo box, or why
- * we were buildig a new combo box every time so I went with caching it.
- */
- private JComboBox comboBox;
-
- /** the items used to populate the combo box */
- private CachingComboBoxModel model;
- private ListCellRenderer renderer;
- Object value;
- private static int height = -1;
- boolean fakeFocusFlag;
-
- /** the listener to be notified on an immediate edit */
- protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
-
- /** hold the original colors of the combo-box */
- private static Color defaultForeground;
- private static Color defaultBackground;
-
- /** "normal" border - assume the default table "focus" border is 1 pixel thick */
- private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
-
-
- // ********** constructors/initialization **********
-
- /**
- * Default constructor.
- */
- private ComboBoxTableCellRenderer() {
- super();
- initialize();
- }
-
- /**
- * Construct a cell renderer that uses the specified combo-box model.
- */
- public ComboBoxTableCellRenderer(ComboBoxModel model) {
- this(new NonCachingComboBoxModel(model));
- }
-
- /**
- * Construct a cell renderer that uses the specified caching combo-box model.
- */
- public ComboBoxTableCellRenderer(CachingComboBoxModel model) {
- this();
- this.model = model;
- }
-
- /**
- * Construct a cell renderer that uses the specified
- * combo-box model and renderer.
- */
- public ComboBoxTableCellRenderer(ComboBoxModel model, ListCellRenderer renderer) {
- this(new NonCachingComboBoxModel(model), renderer);
- }
-
- /**
- * Construct a cell renderer that uses the specified
- * caching combo-box model and renderer.
- */
- public ComboBoxTableCellRenderer(CachingComboBoxModel model, ListCellRenderer renderer) {
- this(model);
- this.renderer = renderer;
- }
-
- protected void initialize() {
- // save the original colors of the combo-box, so we
- // can use them to paint non-selected cells
- if (height == -1) {
- JComboBox cb = new JComboBox();
- cb.addItem("m");
-
- // add in space for the border top and bottom
- height = cb.getPreferredSize().height + 2;
-
- defaultForeground = cb.getForeground();
- defaultBackground = cb.getBackground();
- }
- }
-
- static JLabel prototypeLabel = new JLabel("Prototype", new EmptyIcon(16), SwingConstants.LEADING);
-
- protected JComboBox buildComboBox() {
-
- final JComboBox result = new JComboBox() {
- private boolean fakeFocus;
- @Override
- public boolean hasFocus() {
- return fakeFocus || super.hasFocus();
- }
- @Override
- public void paint(Graphics g) {
- fakeFocus = ComboBoxTableCellRenderer.this.fakeFocusFlag;
- super.paint(g);
- fakeFocus = false;
- }
- //wrap the renderer to deal with the prototypeDisplayValue
- @Override
- public void setRenderer(final ListCellRenderer aRenderer) {
- super.setRenderer(new ListCellRenderer(){
- public Component getListCellRendererComponent(JList list, Object v, int index, boolean isSelected, boolean cellHasFocus) {
- if (v == prototypeLabel) {
- return prototypeLabel;
- }
- return aRenderer.getListCellRendererComponent(list, v, index, isSelected, cellHasFocus);
- }
- });
- }
- @Override
- public int getSelectedIndex() {
- boolean listNotCached = !listIsCached();
- if (listNotCached) {
- cacheList();
- }
-
- int index = super.getSelectedIndex();
-
- if (listNotCached) {
- uncacheList();
- }
- return index;
- }
-
- };
- // stole this code from javax.swing.DefaultCellEditor
- result.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
- result.addActionListener(this.buildActionListener());
- result.addPopupMenuListener(this.buildPopupMenuListener());
-
- //These are used to workaround problems with Swing trying to
- //determine the size of a comboBox with a large model
- result.setPrototypeDisplayValue(prototypeLabel);
- getListBox(result).setPrototypeCellValue(prototypeLabel);
-
- return result;
- }
-
-
- private JList getListBox(JComboBox result) {
- return (JList) ClassTools.fieldValue(result.getUI(), "listBox");
- }
-
-
- private ActionListener buildActionListener() {
- return new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JComboBox cb = (JComboBox) e.getSource();
- Object selectedItem = cb.getSelectedItem();
-
- // Only update the selected item and invoke immediateEdit() if the
- // selected item actually changed, during the initialization of the
- // editing, the model changes and causes this method to be invoked,
- // it causes CR#3963675 to occur because immediateEdit() stop the
- // editing, which is done at the wrong time
- if (ComboBoxTableCellRenderer.this.value != selectedItem) {
- ComboBoxTableCellRenderer.this.value = cb.getSelectedItem();
- ComboBoxTableCellRenderer.this.immediateEdit();
- }
- }
- };
- }
-
- void immediateEdit() {
- if (this.immediateEditListener != null) {
- this.immediateEditListener.immediateEdit();
- }
- }
-
- private PopupMenuListener buildPopupMenuListener() {
- return new PopupMenuListener() {
-
- public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
- if (listIsCached()) {
- uncacheList();
- }
- cacheList();
- }
-
- public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
- if (listIsCached()) {
- uncacheList();
- }
-
- }
-
- public void popupMenuCanceled(PopupMenuEvent e) {
- if (listIsCached()) {
- uncacheList();
- }
- }
- };
- }
-
-
- void cacheList() {
- this.model.cacheList();
- }
-
- void uncacheList() {
- this.model.uncacheList();
- }
-
- boolean listIsCached() {
- return this.model.isCached();
- }
- // ********** TableCellRenderer implementation **********
-
- public Component getTableCellRendererComponent(JTable table, Object val, boolean selected, boolean hasFocus, int row, int column) {
- this.fakeFocusFlag = selected || hasFocus;
- if (this.comboBox == null) {
- this.comboBox = this.buildComboBox();
-
- this.comboBox.setComponentOrientation(table.getComponentOrientation());
- this.comboBox.setModel(this.model);
- if (this.renderer != null) {
- this.comboBox.setRenderer(this.renderer);
- }
- this.comboBox.setFont(table.getFont());
- this.comboBox.setEnabled(table.isEnabled());
- this.comboBox.setBorder(this.border(table, val, selected, hasFocus, row, column));
- }
-
- // We need to go through the model since JComboBox might prevent us from
- // selecting the value. This can happen when the value is not contained
- // in the model, see CR#3950044 for an example
- this.model.setSelectedItem(val);
-
- return this.comboBox;
- }
-
- /**
- * Return the cell's foreground color.
- */
- protected Color foregroundColor(JTable table, Object val, boolean selected, boolean hasFocus, int row, int column) {
- if (selected) {
- if (hasFocus && table.isCellEditable(row, column)) {
- return defaultForeground;
- }
- return table.getSelectionForeground();
- }
- return defaultForeground;
- }
-
- /**
- * Return the cell's background color.
- */
- protected Color backgroundColor(JTable table, Object val, boolean selected, boolean hasFocus, int row, int column) {
- if (selected) {
- if (hasFocus && table.isCellEditable(row, column)) {
- return defaultBackground;
- }
- return table.getSelectionBackground();
- }
- return defaultBackground;
- }
-
- /**
- * Return the cell's border.
- */
- protected Border border(JTable table, Object val, boolean selected, boolean hasFocus, int row, int column) {
- return hasFocus ?
- UIManager.getBorder("Table.focusCellHighlightBorder")
- :
- NO_FOCUS_BORDER;
- }
-
-
- // ********** TableCellEditorAdapter.Renderer implementation **********
-
- public Object getValue() {
- return this.value;
- }
-
- public void setImmediateEditListener(TableCellEditorAdapter.ImmediateEditListener listener) {
- this.immediateEditListener = listener;
- }
-
-
- // ********** public API **********
-
- /**
- * Return the renderer's preferred height. This allows you
- * to set the row height to something the combo-box will look good in....
- */
- public int preferredHeight() {
- return height;
- }
-
-} \ No newline at end of file
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/Displayable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/Displayable.java
deleted file mode 100644
index f5149cfb78..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/Displayable.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.text.Collator;
-import java.util.Comparator;
-import javax.swing.Icon;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * Used by general-purpose UI models and renderers to cast
- * application model objects to something displayable.
- */
-public interface Displayable
- extends Model, Comparable<Displayable>
-{
-
- /**
- * Return a string that can be used to identify the model
- * in a textual UI setting (typically the object's name).
- * When the display string changes, the model should fire
- * the appropriate change notification:
- * this.firePropertyChanged(DISPLAY_STRING_PROPERTY, oldDisplayString, this.displayString());
- */
- String displayString();
- String DISPLAY_STRING_PROPERTY = "displayString";
-
- /**
- * Return an icon that can be used to identify the model
- * in a UI component that supports icons (the icon can be null).
- * When the icon changes, the model should fire
- * the appropriate change notification:
- * this.firePropertyChanged(ICON_PROPERTY, oldIcon, this.icon());
- */
- Icon icon();
- String ICON_PROPERTY = "icon";
-
-
- // ********** helper implementations **********
-
- Collator DEFAULT_COLLATOR = Collator.getInstance();
-
- /**
- * Since all displayable objects must be comparable, provide a
- * typical comparator that can be used to sort a collection of
- * displayable objects.
- * Sort based on display string:
- * - identical objects are equal (which means they cannot
- * co-exist in a SortedSet)
- * - use the default collator (which typically interleaves
- * lower- and upper-case letters)
- * - allow duplicate display strings (from different objects)
- * - try to return consistent results for same object pairs
- */
- Comparator<Displayable> DEFAULT_COMPARATOR =
- new Comparator<Displayable>() {
- public int compare(Displayable d1, Displayable d2) {
- // disallow duplicates based on object identity
- if (d1 == d2) {
- return 0;
- }
-
- // first compare display strings using the default collator
- int result = DEFAULT_COLLATOR.compare(d1.displayString(), d2.displayString());
- if (result != 0) {
- return result;
- }
-
- // then compare using object-id
- result = System.identityHashCode(d1) - System.identityHashCode(d2);
- if (result != 0) {
- return result;
- }
-
- // It's unlikely that we get to this point; but, just in case, we will return -1.
- // Unfortunately, this introduces some mild unpredictability to the sort order
- // (unless the objects are always passed into this method in the same order).
- return -1; // if all else fails, indicate that o1 < o2
- }
- @Override
- public String toString() {
- return "Displayable.DEFAULT_COMPARATOR";
- }
- };
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/EmptyIcon.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/EmptyIcon.java
deleted file mode 100644
index 148308eaa9..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/EmptyIcon.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.Component;
-import java.awt.Graphics;
-import javax.swing.Icon;
-
-/**
- * Implement the Icon interface with an icon that has a size but
- * does not paint anything on the graphics context.
- */
-public class EmptyIcon
- implements Icon
-{
- private final int width;
- private final int height;
-
- public static final EmptyIcon NULL_INSTANCE = new EmptyIcon(0);
-
-
- public EmptyIcon(int width, int height) {
- super();
- this.width = width;
- this.height = height;
- }
-
- public EmptyIcon(int size) {
- this(size, size);
- }
-
-
- // ********** Icon implementation **********
-
- public void paintIcon(Component c, Graphics g, int x, int y) {
- // don't paint anything for an empty icon
- }
-
- public int getIconWidth() {
- return this.width;
- }
-
- public int getIconHeight() {
- return this.height;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java
deleted file mode 100644
index d59f3e04d3..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListBrowser.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import javax.swing.Icon;
-import javax.swing.JComboBox;
-import javax.swing.JOptionPane;
-import javax.swing.ListModel;
-
-/**
- * This implementation of LongListComponent.Browser uses a
- * JOptionPane to prompt the user for the selection. The JOPtionPane
- * is passed a FilteringListPanel to assist the user in making
- * a selection.
- */
-public class FilteringListBrowser<T>
- implements ListChooser.ListBrowser
-{
- private FilteringListPanel<T> panel;
-
- /**
- * Default constructor.
- */
- public FilteringListBrowser() {
- super();
- this.panel = this.buildPanel();
- }
-
- protected FilteringListPanel<T> buildPanel() {
- return new LocalFilteringListPanel<T>();
- }
-
- /**
- * Prompt the user using a JOptionPane with a filtering
- * list panel.
- */
- public void browse(ListChooser chooser) {
- this.initializeCellRenderer(chooser);
-
- int option =
- JOptionPane.showOptionDialog(
- chooser,
- this.message(chooser),
- this.title(chooser),
- this.optionType(chooser),
- this.messageType(chooser),
- this.icon(chooser),
- this.selectionValues(chooser),
- this.initialSelectionValue(chooser)
- );
-
- if (option == JOptionPane.OK_OPTION) {
- chooser.getModel().setSelectedItem(this.panel.selection());
- }
-
- // clear the text field so the list box is re-filtered
- this.panel.textField().setText("");
- }
-
- protected void initializeCellRenderer(JComboBox comboBox) {
- // default behavior should be to use the cell renderer from the combobox.
- this.panel.listBox().setCellRenderer(comboBox.getRenderer());
- }
-
- /**
- * the message can be anything - here we build a component
- */
- protected Object message(JComboBox comboBox) {
- this.panel.setCompleteList(this.convertToArray(comboBox.getModel()));
- this.panel.setSelection(comboBox.getModel().getSelectedItem());
- return this.panel;
- }
-
- protected String title(JComboBox comboBox) {
- return null;
- }
-
- protected int optionType(JComboBox comboBox) {
- return JOptionPane.OK_CANCEL_OPTION;
- }
-
- protected int messageType(JComboBox comboBox) {
- return JOptionPane.QUESTION_MESSAGE;
- }
-
- protected Icon icon(JComboBox comboBox) {
- return null;
- }
-
- protected Object[] selectionValues(JComboBox comboBox) {
- return null;
- }
-
- protected Object initialSelectionValue(JComboBox comboBox) {
- return null;
- }
-
- /**
- * Convert the list of objects in the specified list model
- * into an array.
- */
- protected Object[] convertToArray(ListModel model) {
- int size = model.getSize();
- Object[] result = new Object[size];
- for (int i = 0; i < size; i++) {
- result[i] = model.getElementAt(i);
- }
- return result;
- }
-
-
- // ********** custom panel **********
-
- protected static class LocalFilteringListPanel<S> extends FilteringListPanel<S> {
- protected static final Object[] EMPTY_ARRAY = new Object[0];
-
- protected LocalFilteringListPanel() {
- super(EMPTY_ARRAY, null);
- }
-
- /**
- * Disable the performance tweak because JOptionPane
- * will try open wide enough to disable the horizontal scroll bar;
- * and it looks a bit clumsy.
- */
- @Override
- protected String prototypeCellValue() {
- return null;
- }
-
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java
deleted file mode 100644
index ff17df3305..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/FilteringListPanel.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Font;
-import javax.swing.AbstractListModel;
-import javax.swing.BorderFactory;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.ListCellRenderer;
-import javax.swing.ListModel;
-import javax.swing.ListSelectionModel;
-import javax.swing.border.Border;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import org.eclipse.jpt.utility.internal.SimpleStringMatcher;
-import org.eclipse.jpt.utility.internal.StringConverter;
-import org.eclipse.jpt.utility.internal.StringMatcher;
-
-/**
- * This panel presents an entry field and a list box of choices that
- * allows the user to filter the entries in the list box by entering
- * a pattern in the entry field.
- *
- * By default, two wildcards are allowed in the pattern:
- * '*' will match any set of zero or more characters
- * '?' will match any single character
- *
- * The panel consists of 4 components that can be customized:
- * - 1 text field
- * - 1 list box
- * - 2 labels, one for each of the above
- *
- * Other aspects of the panel's behavior can be changed:
- * - the string converter determines how the objects in the
- * list are converted to strings and compared to the pattern
- * entered in the text field; by default the converter simply
- * uses the result of the object's #toString() method
- * (if you replace the string converter, you will probably
- * want to replace the list box's cell renderer also)
- * - the string matcher can also be changed if you would
- * like different pattern matching behavior than that
- * described above
- * - you can specify the maximum size of the list - this may
- * force the user to enter a pattern restrictive enough
- * to result in a list smaller than the maximum size; the
- * default is -1, which disables the restriction
- *
- * This panel is not a typical panel, in the sense that it does not share
- * its model with clients via value models. Instead, this panel's model
- * is set and queried directly because it is designed to be used in a
- * dialog that directs the user's behavior (as opposed to a "normal"
- * window).
- */
-public class FilteringListPanel<T> extends JPanel {
-
- /**
- * The complete list of available choices
- * (as opposed to the partial list held by the list box).
- */
- private Object[] completeList;
-
- /**
- * An adapter used to convert the objects in the list
- * to strings so they can be run through the matcher
- * and displayed in the text field.
- */
- StringConverter<T> stringConverter;
-
- /** The text field. */
- private JTextField textField;
- private JLabel textFieldLabel;
- private DocumentListener textFieldListener;
-
- /** The list box. */
- private JList listBox;
- private JLabel listBoxLabel;
-
- /** The maximum number of entries displayed in the list box. */
- private int maxListSize;
-
- /**
- * The matcher used to filter the list against
- * the pattern entered in the text field. By default,
- * this allows the two wildcard characters described in
- * the class comment.
- */
- private StringMatcher stringMatcher;
-
- /**
- * Performance tweak: We use this buffer instead of
- * a temporary variable during filtering so we don't have
- * to keep re-allocating it.
- */
- private Object[] buffer;
-
- private static final Border TEXT_FIELD_LABEL_BORDER = BorderFactory.createEmptyBorder(0, 0, 5, 0);
- private static final Border LIST_BOX_LABEL_BORDER = BorderFactory.createEmptyBorder(5, 0, 5, 0);
-
-
- // ********** constructors **********
-
- /**
- * Construct a FilteringListPanel with the specified list of choices
- * and initial selection. Use the default string converter to convert the
- * choices and selection to strings (which simply calls #toString() on
- * the objects).
- */
- public FilteringListPanel(Object[] completeList, Object initialSelection) {
- this(completeList, initialSelection, StringConverter.Default.<T>instance());
- }
-
- /**
- * Construct a FilteringListPanel with the specified list of choices
- * and initial selection. Use the specified string converter to convert the
- * choices and selection to strings.
- */
- public FilteringListPanel(Object[] completeList, Object initialSelection, StringConverter<T> stringConverter) {
- super(new BorderLayout());
- this.completeList = completeList;
- this.stringConverter = stringConverter;
- this.initialize(initialSelection);
- }
-
-
- // ********** initialization **********
-
- private void initialize(Object initialSelection) {
- this.maxListSize = this.defaultMaxListSize();
- this.buffer = this.buildBuffer();
-
- this.textFieldListener = this.buildTextFieldListener();
-
- this.stringMatcher = this.buildStringMatcher();
-
- this.initializeLayout(initialSelection);
- }
-
- private Object[] buildBuffer() {
- return new Object[this.max()];
- }
-
- /**
- * Return the current max number of entries allowed in the list box.
- */
- private int max() {
- if (this.maxListSize == -1) {
- return this.completeList.length;
- }
- return Math.min(this.maxListSize, this.completeList.length);
- }
-
- /**
- * Build a listener that will listen to changes in the text field
- * and filter the list appropriately.
- */
- private DocumentListener buildTextFieldListener() {
- return new DocumentListener() {
- public void insertUpdate(DocumentEvent e) {
- FilteringListPanel.this.filterList();
- }
- public void changedUpdate(DocumentEvent e) {
- FilteringListPanel.this.filterList();
- }
- public void removeUpdate(DocumentEvent e) {
- FilteringListPanel.this.filterList();
- }
- @Override
- public String toString() {
- return "text field listener";
- }
- };
- }
-
- private int defaultMaxListSize() {
- return -1;
- }
-
- private StringMatcher buildStringMatcher() {
- return new SimpleStringMatcher<T>();
- }
-
- private void initializeLayout(Object initialSelection) {
- // text field
- JPanel textFieldPanel = new JPanel(new BorderLayout());
- this.textFieldLabel = new JLabel();
- this.textFieldLabel.setBorder(TEXT_FIELD_LABEL_BORDER);
- textFieldPanel.add(this.textFieldLabel, BorderLayout.NORTH);
-
- this.textField = new JTextField();
- this.textField.getDocument().addDocumentListener(this.textFieldListener);
- this.textFieldLabel.setLabelFor(this.textField);
- textFieldPanel.add(this.textField, BorderLayout.CENTER);
-
- this.add(textFieldPanel, BorderLayout.NORTH);
-
- // list box
- JPanel listBoxPanel = new JPanel(new BorderLayout());
- this.listBoxLabel = new JLabel();
- this.listBoxLabel.setBorder(LIST_BOX_LABEL_BORDER);
- listBoxPanel.add(this.listBoxLabel, BorderLayout.NORTH);
-
- this.listBox = new JList();
- this.listBox.setDoubleBuffered(true);
- this.listBox.setModel(this.buildPartialArrayListModel(this.completeList, this.max()));
- this.listBox.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- // performance tweak(?)
- this.listBox.setPrototypeCellValue(this.prototypeCellValue());
- this.listBox.setPrototypeCellValue(null);
- this.listBox.setCellRenderer(this.buildDefaultCellRenderer());
- this.listBoxLabel.setLabelFor(this.listBox);
- // bug 2777802 - scroll bars shouldn't be on the tab sequence
- JScrollPane listBoxScrollPane = new JScrollPane(this.listBox);
- listBoxScrollPane.getHorizontalScrollBar().setFocusable(false);
- listBoxScrollPane.getVerticalScrollBar().setFocusable(false);
- listBoxPanel.add(listBoxScrollPane, BorderLayout.CENTER);
-
- // initialize the widgets
- this.listBox.setSelectedValue(initialSelection, true);
- this.textField.select(0, this.textField.getText().length());
-
- this.add(listBoxPanel, BorderLayout.CENTER);
- }
-
-
- // ********** public API **********
-
- public Object selection() {
- return this.listBox.getSelectedValue();
- }
-
- public void setSelection(Object selection) {
- this.listBox.setSelectedValue(selection, true);
- }
-
- public Object[] completeList() {
- return this.completeList;
- }
-
- /**
- * rebuild the filtering buffer and re-apply the filter
- * to the new list
- */
- public void setCompleteList(Object[] completeList) {
- this.completeList = completeList;
- if (this.buffer.length < this.max()) {
- // the buffer will never shrink - might want to re-consider... ~bjv
- this.buffer = this.buildBuffer();
- }
- this.filterList();
- }
-
- public int maxListSize() {
- return this.maxListSize;
- }
-
- public void setMaxListSize(int maxListSize) {
- this.maxListSize = maxListSize;
- if (this.buffer.length < this.max()) {
- // the buffer will never shrink - might want to re-consider... ~bjv
- this.buffer = this.buildBuffer();
- }
- this.filterList();
- }
-
- public StringConverter<T> stringConverter() {
- return this.stringConverter;
- }
-
- /**
- * apply the new filter to the list
- */
- public void setStringConverter(StringConverter<T> stringConverter) {
- this.stringConverter = stringConverter;
- this.filterList();
- }
-
- /**
- * allow client code to access the text field
- * (so we can set the focus)
- */
- public JTextField textField() {
- return this.textField;
- }
-
- /**
- * allow client code to access the text field label
- */
- public JLabel textFieldLabel() {
- return this.textFieldLabel;
- }
-
- /**
- * convenience method
- */
- public void setTextFieldLabelText(String text) {
- this.textFieldLabel.setText(text);
- }
-
- /**
- * allow client code to access the list box
- * (so we can add mouse listeners for double-clicking)
- */
- public JList listBox() {
- return this.listBox;
- }
-
- /**
- * convenience method
- */
- public void setListBoxCellRenderer(ListCellRenderer renderer) {
- this.listBox.setCellRenderer(renderer);
- }
-
- /**
- * allow client code to access the list box label
- */
- public JLabel listBoxLabel() {
- return this.listBoxLabel;
- }
-
- /**
- * convenience method
- */
- public void setListBoxLabelText(String text) {
- this.listBoxLabel.setText(text);
- }
-
- /**
- * convenience method
- */
- public void setComponentsFont(Font font) {
- this.textFieldLabel.setFont(font);
- this.textField.setFont(font);
- this.listBoxLabel.setFont(font);
- this.listBox.setFont(font);
- }
-
- public StringMatcher stringMatcher() {
- return this.stringMatcher;
- }
-
- /**
- * re-apply the filter to the list
- */
- public void setStringMatcher(StringMatcher stringMatcher) {
- this.stringMatcher = stringMatcher;
- this.filterList();
- }
-
-
- // ********** internal methods **********
-
- /**
- * Allow subclasses to disable performance tweak
- * by returning null here.
- */
- protected String prototypeCellValue() {
- return "==========> A_STRING_THAT_IS_DEFINITELY_LONGER_THAN_EVERY_STRING_IN_THE_LIST <==========";
- }
-
- /**
- * By default, use the string converter to build the text
- * used by the list box's cell renderer.
- */
- protected ListCellRenderer buildDefaultCellRenderer() {
- return new SimpleListCellRenderer() {
- @Override
- @SuppressWarnings("unchecked")
- protected String buildText(Object value) {
- return FilteringListPanel.this.stringConverter.convertToString((T) value);
- }
- };
- }
-
- /**
- * Something has changed that requires us to filter the list.
- *
- * This method is synchronized because a fast typist can
- * generate events quicker than we can filter the list. (? ~bjv)
- */
- synchronized void filterList() {
- // temporarily stop listening to the list box selection, since we will
- // be changing the selection during the filtering and don't want
- // that to affect the text field
- this.filterList(this.textField.getText());
- }
-
- /**
- * Filter the contents of the list box to match the
- * specified pattern.
- */
- private void filterList(String pattern) {
- if (pattern.length() == 0) {
- this.listBox.setModel(this.buildPartialArrayListModel(this.completeList, this.max()));
- } else {
- this.stringMatcher.setPatternString(pattern);
- int j = 0;
- int len = this.completeList.length;
- int max = this.max();
- for (int i = 0; i < len; i++) {
- if (this.stringMatcher.matches(this.stringConverter.convertToString(this.entry(i)))) {
- this.buffer[j++] = this.completeList[i];
- }
- if (j == max) {
- break;
- }
- }
- this.listBox.setModel(this.buildPartialArrayListModel(this.buffer, j));
- }
-
- // after filtering the list, determine the appropriate selection
- if (this.listBox.getModel().getSize() == 0) {
- this.listBox.getSelectionModel().clearSelection();
- } else {
- this.listBox.getSelectionModel().setAnchorSelectionIndex(0);
- this.listBox.getSelectionModel().setLeadSelectionIndex(0);
- this.listBox.ensureIndexIsVisible(0);
- }
- }
-
- /**
- * minimize scope of suppressed warnings
- */
- @SuppressWarnings("unchecked")
- private T entry(int index) {
- return (T) this.completeList[index];
- }
-
- /**
- * Build a list model that wraps only a portion of the specified array.
- * The model will include the array entries from 0 to (size - 1).
- */
- private ListModel buildPartialArrayListModel(final Object[] array, final int size) {
- return new AbstractListModel() {
- public int getSize() {
- return size;
- }
- public Object getElementAt(int index) {
- return array[index];
- }
- };
- }
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java
deleted file mode 100644
index 9abc2e58f8..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/ListChooser.java
+++ /dev/null
@@ -1,425 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.AWTEvent;
-import java.awt.AWTException;
-import java.awt.Component;
-import java.awt.EventQueue;
-import java.awt.Point;
-import java.awt.Robot;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.awt.event.MouseEvent;
-import javax.swing.ComboBoxModel;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.ListCellRenderer;
-import javax.swing.SwingConstants;
-import javax.swing.event.PopupMenuEvent;
-import javax.swing.event.PopupMenuListener;
-import javax.swing.plaf.basic.BasicComboBoxUI;
-import org.eclipse.jpt.utility.internal.ClassTools;
-
-/**
- * This component provides a way to handle selecting an item from a
- * list that may grow too large to be handled conveniently by a combo-box.
- * If the list's size is less than the designated "long" list size,
- * the choice list will be displayed in a normal combo-box popup;
- * otherwise, a dialog will be used to prompt the user to choose a selection.
- *
- * To change the browse mechanism, subclasses may
- * - override the method #buildBrowser()
- * - override the method #browse(), in which case the method
- * #buildBrowser() may be ignored.
- */
-public class ListChooser
- extends JComboBox
-{
-
- /** the size of a "long" list - anything smaller is a "short" list */
- int longListSize = DEFAULT_LONG_LIST_SIZE;
-
- /** the default size of a "long" list, which is 20 (to match JOptionPane's behavior) */
- public static final int DEFAULT_LONG_LIST_SIZE = 20;
-
- /** property change associated with long list size */
- public static final String LONG_LIST_SIZE_PROPERTY = "longListSize";
-
- static JLabel prototypeLabel = new JLabel("Prototype", new EmptyIcon(17), SwingConstants.LEADING);
-
- /**
- * whether the chooser is choosable. if a chooser is not choosable,
- * it only serves as a display widget. a user may not change its
- * selected value.
- */
- boolean choosable = true;
-
- /** property change associated with choosable */
- public static final String CHOOSABLE_PROPERTY = "choosable";
-
- /** the browser used to make a selection from the long list - typically via a dialog */
- private ListBrowser browser;
-
- private NodeSelector nodeSelector;
-
- /** INTERNAL - The popup is being shown. Used to prevent infinite loop. */
- boolean popupAlreadyInProgress;
-
-
- // **************** Constructors ******************************************
-
- /**
- * Construct a list chooser for the specified model.
- */
- public ListChooser(ComboBoxModel model) {
- this(model, new NodeSelector.DefaultNodeSelector());
- }
-
- public ListChooser(CachingComboBoxModel model) {
- this(model, new NodeSelector.DefaultNodeSelector());
- }
-
- public ListChooser(ComboBoxModel model, NodeSelector nodeSelector) {
- this(new NonCachingComboBoxModel(model), nodeSelector);
- }
-
- public ListChooser(CachingComboBoxModel model, NodeSelector nodeSelector) {
- super(model);
- this.initialize();
- this.nodeSelector = nodeSelector;
- }
- // **************** Initialization ****************************************
-
- protected void initialize() {
- this.addPopupMenuListener(this.buildPopupMenuListener());
- this.setRenderer(new DefaultListCellRenderer());
- this.addKeyListener(buildF3KeyListener());
-
- //These are used to workaround problems with Swing trying to
- //determine the size of a comboBox with a large model
- setPrototypeDisplayValue(prototypeLabel);
- listBox().setPrototypeCellValue(prototypeLabel);
- }
-
-
- private JList listBox() {
- return (JList) ClassTools.fieldValue(this.ui, "listBox");
- }
-
- /**
- * When the popup is about to be shown, the event is consumed, and
- * PopupHandler determines whether to reshow the popup or to show
- * the long list browser.
- */
- private PopupMenuListener buildPopupMenuListener() {
- return new PopupMenuListener() {
- public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
- ListChooser.this.aboutToShowPopup();
- }
- public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
- // do nothing
- }
- public void popupMenuCanceled(PopupMenuEvent e) {
- // do nothing
- }
- @Override
- public String toString() {
- return "pop-up menu listener";
- }
- };
- }
-
- /**
- * If this code is being reached due to the PopupHandler already being in progress,
- * then do nothing. Otherwise, set the flag to true and launch the PopupHandler.
- */
- void aboutToShowPopup() {
- if (this.popupAlreadyInProgress) {
- return;
- }
-
- this.popupAlreadyInProgress = true;
- EventQueue.invokeLater(new PopupHandler());
- }
-
-
- private KeyListener buildF3KeyListener() {
- return new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e) {
- if (e.getKeyCode() == KeyEvent.VK_F3) {
- goToSelectedItem();
- }
- }
- @Override
- public String toString() {
- return "F3 key listener";
- }
- };
- }
-
- public void goToSelectedItem() {
- if (getSelectedItem() != null) {
- ListChooser.this.nodeSelector.selectNodeFor(getSelectedItem());
- }
- }
-
- // **************** Browsing **********************************************
-
- /**
- * Lazily initialize because subclasses may have further initialization to do
- * before browser can be built.
- */
- protected void browse() {
- if (this.browser == null) {
- this.browser = this.buildBrowser();
- }
-
- this.browser.browse(this);
- }
-
- /**
- * Return the "browser" used to make a selection from the long list,
- * typically via a dialog.
- */
- protected ListChooser.ListBrowser buildBrowser() {
- return new SimpleListBrowser();
- }
-
-
- // **************** Choosable functionality *******************************
-
- /** override behavior - consume selection if chooser is not choosable */
- @Override
- public void setSelectedIndex(int anIndex) {
- if (this.choosable) {
- super.setSelectedIndex(anIndex);
- }
- }
-
- private void updateArrowButton() {
- try {
- BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI();
- JButton arrowButton = (JButton) ClassTools.fieldValue(comboBoxUi, "arrowButton");
- arrowButton.setEnabled(this.isEnabled() && this.choosable);
- }
- catch (Exception e) {
- // this is a huge hack to try and make the combo box look right,
- // so if it doesn't work, just swallow the exception
- }
- }
-
-
- // **************** List Caching *******************************
-
- void cacheList() {
- ((CachingComboBoxModel) getModel()).cacheList();
- }
-
- void uncacheList() {
- ((CachingComboBoxModel) getModel()).uncacheList();
- }
-
- boolean listIsCached() {
- return ((CachingComboBoxModel) getModel()).isCached();
- }
-
- // **************** Public ************************************************
-
- public int longListSize() {
- return this.longListSize;
- }
-
- public void setLongListSize(int newLongListSize) {
- int oldLongListSize = this.longListSize;
- this.longListSize = newLongListSize;
- this.firePropertyChange(LONG_LIST_SIZE_PROPERTY, oldLongListSize, newLongListSize);
- }
-
- public boolean isChoosable() {
- return this.choosable;
- }
-
- public void setChoosable(boolean newValue) {
- boolean oldValue = this.choosable;
- this.choosable = newValue;
- this.firePropertyChange(CHOOSABLE_PROPERTY, oldValue, newValue);
- this.updateArrowButton();
- }
-
- // **************** Handle selecting null as a value **********************
-
- private boolean selectedIndexIsNoneSelectedItem(int index) {
- return index == -1 &&
- getModel().getSize() > 0 &&
- getModel().getElementAt(0) == null;
- }
-
- @Override
- public int getSelectedIndex() {
- boolean listNotCached = !listIsCached();
- if (listNotCached) {
- cacheList();
- }
-
- int index = super.getSelectedIndex();
-
- // Use index 0 to show the <none selected> item since the actual value is
- // null and JComboBox does not handle null values
- if (selectedIndexIsNoneSelectedItem(index)) {
- index = 0;
- }
-
- if (listNotCached) {
- uncacheList();
- }
- return index;
- }
-
- //wrap the renderer to deal with the prototypeDisplayValue
- @Override
- public void setRenderer(final ListCellRenderer aRenderer) {
- super.setRenderer(new ListCellRenderer(){
- public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- if (value == prototypeLabel) {
- return prototypeLabel;
- }
- return aRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
- }
- });
- }
-
-
- // **************** Member classes ****************************************
-
- /**
- * Define the API required by this ListChooser when it must
- * prompt the user to select an item from the "long" list.
- */
- public interface ListBrowser
- {
- /**
- * Prompt the user to make a selection from the specified
- * combo-box's model.
- */
- void browse(ListChooser parentChooser);
- }
-
-
- /**
- * Runnable class that consumes popup window and determines whether
- * to reshow popup or to launch browser, based on the size of the list.
- */
- private class PopupHandler
- implements Runnable
- {
- /** The mouse event */
- private MouseEvent lastMouseEvent;
-
- /** The component from which the last mouse event was thrown */
- private JComponent eventComponent;
-
- /** The location of the component at the time the last mouse event was thrown */
- private Point componentLocation;
-
- /** The location of the mouse at the time the last mouse event was thrown */
- private Point mouseLocation;
-
-
- PopupHandler() {
- this.initialize();
- }
-
- private void initialize() {
- AWTEvent event = EventQueue.getCurrentEvent();
-
- if (event instanceof MouseEvent) {
- this.lastMouseEvent = (MouseEvent) event;
- this.eventComponent = (JComponent) this.lastMouseEvent.getSource();
- this.componentLocation = this.eventComponent.getLocationOnScreen();
- this.mouseLocation = this.lastMouseEvent.getPoint();
- }
- else {
- this.eventComponent = null;
- this.componentLocation = null;
- this.mouseLocation = null;
- }
- }
-
- public void run() {
- ListChooser.this.hidePopup();
-
- cacheList();
- if (ListChooser.this.choosable == true) {
- // If the combo box model is of sufficient length, the browser will be shown.
- // Asking the combo box model for its size should be enough to ensure that
- // its size is recalculated.
- if (ListChooser.this.getModel().getSize() > ListChooser.this.longListSize) {
- this.checkComboBoxButton();
- ListChooser.this.browse();
- }
- else {
- ListChooser.this.showPopup();
- this.checkMousePosition();
- }
- }
- if (listIsCached()) {
- uncacheList();
- }
-
- ListChooser.this.popupAlreadyInProgress = false;
- }
-
- /** If this is not done, the button never becomes un-pressed */
- private void checkComboBoxButton() {
- try {
- BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI();
- JButton arrowButton = (JButton) ClassTools.fieldValue(comboBoxUi, "arrowButton");
- arrowButton.getModel().setPressed(false);
- }
- catch (Exception e) {
- // this is a huge hack to try and make the combo box look right,
- // so if it doesn't work, just swallow the exception
- }
- }
-
- /**
- * Moves the mouse back to its original position before any jiggery pokery that we've done.
- */
- private void checkMousePosition() {
- if (this.eventComponent == null) {
- return;
- }
-
- final Point newComponentLocation = this.eventComponent.getLocationOnScreen();
- boolean componentMoved =
- newComponentLocation.x - this.componentLocation.x != 0
- || newComponentLocation.y - this.componentLocation.y != 0;
-
- if (componentMoved) {
- try {
- new Robot().mouseMove(
- newComponentLocation.x + this.mouseLocation.x,
- newComponentLocation.y + this.mouseLocation.y
- );
- }
- catch (AWTException ex) {
- // move failed - do nothing
- }
- }
- }
- }
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NodeSelector.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NodeSelector.java
deleted file mode 100644
index f8b4d148e5..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NodeSelector.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-/**
- * This will be called when the user presses F3 or chooses
- * 'Go To' in the context menu
- */
-public interface NodeSelector
-{
- /**
- * Select the appropriate Node in the tree or the editor panel.
- */
- void selectNodeFor(Object item);
-
- /**
- * This NodeSelector will do nothing when selectNodeFor(Object) is called
- */
- class DefaultNodeSelector implements NodeSelector {
-
- public void selectNodeFor(Object item) {
- //default is to do nothing
- }
- }
-} \ No newline at end of file
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NonCachingComboBoxModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NonCachingComboBoxModel.java
deleted file mode 100644
index ee7226457f..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/NonCachingComboBoxModel.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import javax.swing.ComboBoxModel;
-import javax.swing.event.ListDataListener;
-
-/**
- * This implementation of the CachingComboBoxModel interface can be used
- * whenever there is no need for caching (i.e. the contents of the selection
- * list can be generated with little latency). All the normal ComboBoxModel
- * behavior is delegated to a client-supplied ComboBoxModel.
- */
-public class NonCachingComboBoxModel implements CachingComboBoxModel {
- private ComboBoxModel wrappedComboBoxModel;
-
- public NonCachingComboBoxModel(ComboBoxModel wrappedComboBoxModel) {
- this.wrappedComboBoxModel = wrappedComboBoxModel;
- }
-
-
- // ********** CachingComboBoxModel implementation **********
-
- public void cacheList() {
- //do nothing
- }
-
- public void uncacheList() {
- //do nothing
- }
-
- public boolean isCached() {
- return false;
- }
-
-
- // ********** ComboBoxModel implementation **********
-
- public void setSelectedItem(Object anItem) {
- this.wrappedComboBoxModel.setSelectedItem(anItem);
- }
-
- public Object getSelectedItem() {
- return this.wrappedComboBoxModel.getSelectedItem();
- }
-
-
- // ********** ListModel implementation **********
-
- public int getSize() {
- return this.wrappedComboBoxModel.getSize();
- }
-
- public Object getElementAt(int index) {
- return this.wrappedComboBoxModel.getElementAt(index);
- }
-
- public void addListDataListener(ListDataListener l) {
- this.wrappedComboBoxModel.addListDataListener(l);
- }
-
- public void removeListDataListener(ListDataListener l) {
- this.wrappedComboBoxModel.removeListDataListener(l);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleDisplayable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleDisplayable.java
deleted file mode 100644
index 8d5aa452cf..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleDisplayable.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import javax.swing.Icon;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-
-/**
- * This implementation of Displayable converts any Object
- * to a Displayable. Subclass it to override #displayString() and
- * #icon() if necessary. Change notification will be fired if the
- * object is changed.
- *
- * This can be used for Strings - the display string
- * will simply be the String itself.
- */
-public class SimpleDisplayable
- extends AbstractModel
- implements Displayable
-{
- /** The object to be converted to a Displayable. */
- protected Object object;
-
-
- /**
- * Construct a displayable for the specified object.
- */
- public SimpleDisplayable(Object object) {
- super();
- this.object = object;
- }
-
- public SimpleDisplayable(boolean b) {
- this(Boolean.valueOf(b));
- }
-
- public SimpleDisplayable(char c) {
- this(new Character(c));
- }
-
- public SimpleDisplayable(byte b) {
- this(new Byte(b));
- }
-
- public SimpleDisplayable(short s) {
- this(new Short(s));
- }
-
- public SimpleDisplayable(int i) {
- this(new Integer(i));
- }
-
- public SimpleDisplayable(long l) {
- this(new Long(l));
- }
-
- public SimpleDisplayable(float f) {
- this(new Float(f));
- }
-
- public SimpleDisplayable(double d) {
- this(new Double(d));
- }
-
-
- // ********** Displayable implementation **********
-
- public String displayString() {
- return this.object.toString();
- }
-
- public Icon icon() {
- return null;
- }
-
-
- // ********** Comparable implementation **********
-
- public int compareTo(Displayable o) {
- return DEFAULT_COMPARATOR.compare(this, o);
- }
-
-
- // ********** accessors **********
-
- public Object getObject() {
- return this.object;
- }
-
- public void setObject(Object object) {
- String oldDisplayString = this.displayString();
- Icon oldIcon = this.icon();
- this.object = object;
- this.firePropertyChanged(DISPLAY_STRING_PROPERTY, oldDisplayString, this.displayString());
- this.firePropertyChanged(ICON_PROPERTY, oldIcon, this.icon());
- }
-
- public boolean getBoolean() {
- return ((Boolean) this.object).booleanValue();
- }
-
- public void setBoolean(boolean b) {
- this.setObject(Boolean.valueOf(b));
- }
-
- public char getChar() {
- return ((Character) this.object).charValue();
- }
-
- public void setChar(char c) {
- this.setObject(new Character(c));
- }
-
- public byte getByte() {
- return ((Byte) this.object).byteValue();
- }
-
- public void setByte(byte b) {
- this.setObject(new Byte(b));
- }
-
- public short getShort() {
- return ((Short) this.object).shortValue();
- }
-
- public void setShort(short s) {
- this.setObject(new Short(s));
- }
-
- public int getInt() {
- return ((Integer) this.object).intValue();
- }
-
- public void setInt(int i) {
- this.setObject(new Integer(i));
- }
-
- public long getLong() {
- return ((Long) this.object).longValue();
- }
-
- public void setLong(long l) {
- this.setObject(new Long(l));
- }
-
- public float getFloat() {
- return ((Float) this.object).floatValue();
- }
-
- public void setFloat(float f) {
- this.setObject(new Float(f));
- }
-
- public double getDouble() {
- return ((Double) this.object).doubleValue();
- }
-
- public void setDouble(double d) {
- this.setObject(new Double(d));
- }
-
-
- // ********** override methods **********
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append(this.object);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListBrowser.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListBrowser.java
deleted file mode 100644
index 7215c6a387..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListBrowser.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import javax.swing.Icon;
-import javax.swing.JComboBox;
-import javax.swing.JOptionPane;
-import javax.swing.ListModel;
-
-/**
- * This implementation of ListChooser.Browser uses a
- * JOptionPane to prompt the user for the selection. Subclasses
- * can change the dialog's title, message, and/or icon.
- */
-public class SimpleListBrowser
- implements ListChooser.ListBrowser
-{
- /** Default constructor */
- protected SimpleListBrowser() {
- super();
- }
-
- /**
- * Prompt the user using a JOptionPane.
- */
- public void browse(ListChooser chooser) {
- Object selection =
- JOptionPane.showInputDialog(
- chooser,
- this.message(chooser),
- this.title(chooser),
- this.messageType(chooser),
- this.icon(chooser),
- this.selectionValues(chooser),
- this.initialSelectionValue(chooser)
- );
-
- if (selection != null) {
- chooser.getModel().setSelectedItem(selection);
- }
- }
-
- protected Object message(JComboBox comboBox) {
- return null;
- }
-
- protected String title(JComboBox comboBox) {
- return null;
- }
-
- protected int messageType(JComboBox comboBox) {
- return JOptionPane.QUESTION_MESSAGE;
- }
-
- protected Icon icon(JComboBox comboBox) {
- return null;
- }
-
- protected Object[] selectionValues(JComboBox comboBox) {
- return this.convertToArray(comboBox.getModel());
- }
-
- protected Object initialSelectionValue(JComboBox comboBox) {
- return comboBox.getModel().getSelectedItem();
- }
-
- /**
- * Convert the list of objects in the specified list model
- * into an array.
- */
- protected Object[] convertToArray(ListModel model) {
- int size = model.getSize();
- Object[] result = new Object[size];
- for (int i = 0; i < size; i++) {
- result[i] = model.getElementAt(i);
- }
- return result;
- }
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListCellRenderer.java
deleted file mode 100644
index ea649ba33d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SimpleListCellRenderer.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.Component;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.Icon;
-import javax.swing.JList;
-
-/**
- * This renderer should behave the same as the DefaultListCellRenderer;
- * but it slightly refactors the calculation of the icon and text of the list
- * cell so that subclasses can easily override the methods that build
- * the icon and text.
- *
- * In most cases, you need only override:
- * #buildIcon(Object value)
- * #buildText(Object value)
- */
-public class SimpleListCellRenderer
- extends DefaultListCellRenderer
-{
-
- /**
- * Construct a simple renderer.
- */
- public SimpleListCellRenderer() {
- super();
- }
-
- @Override
- public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- // substitute null for the cell value so nothing is drawn initially...
- super.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus);
- this.setOpaque(true);
-
- // ...then set the icon and text manually
- this.setIcon(this.buildIcon(list, value, index, isSelected, cellHasFocus));
- this.setText(this.buildText(list, value, index, isSelected, cellHasFocus));
-
- this.setToolTipText(this.buildToolTipText(list, value, index, isSelected, cellHasFocus));
-
- // the context will be initialized only if a reader is running
- if (this.accessibleContext != null) {
- this.accessibleContext.setAccessibleName(this.buildAccessibleName(list, value, index, isSelected, cellHasFocus));
- }
-
- return this;
- }
-
- /**
- * Return the icon representation of the specified cell
- * value and other settings. (Even more settings are
- * accessible via inherited getters: hasFocus, isEnabled, etc.)
- */
- protected Icon buildIcon(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- return this.buildIcon(value);
- }
-
- /**
- * Return the icon representation of the specified cell
- * value. The default is to display no icon at all unless the
- * value itself is an icon.
- */
- protected Icon buildIcon(Object value) {
- // replicate the default behavior
- return (value instanceof Icon) ? (Icon) value : null;
- }
-
- /**
- * Return the textual representation of the specified cell
- * value and other settings. (Even more settings are
- * accessible via inherited getters: hasFocus, isEnabled, etc.)
- */
- protected String buildText(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- return this.buildText(value);
- }
-
- /**
- * Return the textual representation of the specified cell
- * value. The default is to display the object's default string
- * representation (as returned by #toString()); unless the
- * value itself is an icon, in which case no text is displayed.
- */
- protected String buildText(Object value) {
- return (value instanceof Icon) ? "" : ((value == null) ? "" : value.toString());
- }
-
- /**
- * Return the text displayed when the cursor lingers over the specified cell.
- * (Even more settings are accessible via inherited getters: hasFocus, isEnabled, etc.)
- */
- protected String buildToolTipText(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- return this.buildToolTipText(value);
- }
-
- /**
- * Return the text displayed when the cursor lingers over the specified cell.
- */
- protected String buildToolTipText(Object value) {
- return null;
- }
-
- /**
- * Return the accessible name to be given to the component used to render
- * the given value and other settings. (Even more settings are accessible via
- * inherited getters: hasFocus, isEnabled, etc.)
- */
- protected String buildAccessibleName(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- return this.buildAccessibleName(value);
- }
-
- /**
- * Return the accessible name to be given to the component used to render
- * the given value.
- */
- protected String buildAccessibleName(Object value) {
- return null;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java
deleted file mode 100644
index a15e16a570..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/SpinnerTableCellRenderer.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.Color;
-import java.awt.Component;
-import javax.swing.BorderFactory;
-import javax.swing.JComponent;
-import javax.swing.JSpinner;
-import javax.swing.JTable;
-import javax.swing.SpinnerModel;
-import javax.swing.UIManager;
-import javax.swing.border.Border;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-/**
- * Make the cell look like a spinner.
- */
-public class SpinnerTableCellRenderer implements TableCellEditorAdapter.Renderer {
-
- /** the component used to paint the cell */
- protected JSpinner spinner;
-
- /** the listener to be notified on an immediate edit */
- protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
-
-
- // ********** constructors/initialization **********
-
- /**
- * Construct a cell renderer that uses the default
- * spinner model, which is a "number" model.
- */
- public SpinnerTableCellRenderer() {
- super();
- this.initialize();
- }
-
- /**
- * Construct a cell renderer that uses the specified
- * spinner model, which will determine how the values are displayed.
- */
- public SpinnerTableCellRenderer(SpinnerModel model) {
- this();
- this.setModel(model);
- }
-
- protected void initialize() {
- this.spinner = this.buildSpinner();
- }
-
- protected JSpinner buildSpinner() {
- JSpinner s = new JSpinner();
- s.addChangeListener(this.buildChangeListener());
- return s;
- }
-
- private ChangeListener buildChangeListener() {
- return new ChangeListener() {
- public void stateChanged(ChangeEvent e) {
- if (SpinnerTableCellRenderer.this.immediateEditListener != null) {
- SpinnerTableCellRenderer.this.immediateEditListener.immediateEdit();
- }
- }
- };
- }
-
-
- // ********** TableCellRenderer implementation **********
-
- public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- this.spinner.setComponentOrientation(table.getComponentOrientation());
- this.spinner.setFont(table.getFont());
- this.spinner.setEnabled(table.isEnabled());
-
- JComponent editor = this.editor();
- editor.setForeground(this.foregroundColor(table, value, selected, hasFocus, row, column));
- editor.setBackground(this.backgroundColor(table, value, selected, hasFocus, row, column));
- this.spinner.setBorder(this.border(table, value, selected, hasFocus, row, column));
-
- this.setValue(value);
- return this.spinner;
- }
-
- /**
- * Return the cell's foreground color.
- */
- protected Color foregroundColor(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- if (selected) {
- if (hasFocus && table.isCellEditable(row, column)) {
- return UIManager.getColor("Table.focusCellForeground");
- }
- return table.getSelectionForeground();
- }
- return table.getForeground();
- }
-
- /**
- * Return the cell's background color.
- */
- protected Color backgroundColor(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- if (selected) {
- if (hasFocus && table.isCellEditable(row, column)) {
- return UIManager.getColor("Table.focusCellBackground");
- }
- return table.getSelectionBackground();
- }
- return table.getBackground();
- }
-
- /**
- * Return the cell's border.
- */
- protected Border border(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
- if (hasFocus) {
- return UIManager.getBorder("Table.focusCellHighlightBorder");
- }
- if (selected) {
- return BorderFactory.createLineBorder(table.getSelectionBackground(), 1);
- }
- return BorderFactory.createLineBorder(table.getBackground(), 1);
- }
-
- /**
- * Return the editor component whose colors should be set
- * by the renderer.
- */
- protected JComponent editor() {
- JComponent editor = this.spinner.getEditor();
- if (editor instanceof JSpinner.DefaultEditor) {
- // typically, the editor will be the default or one of its subclasses...
- editor = ((JSpinner.DefaultEditor) editor).getTextField();
- }
- return editor;
- }
-
- /**
- * Set the spinner's value
- */
- protected void setValue(Object value) {
- // CR#3999318 - This null check needs to be removed once JDK bug is fixed
- if (value == null) {
- value = new Integer(0);
- }
- this.spinner.setValue(value);
- }
-
-
- // ********** TableCellEditorAdapter.Renderer implementation **********
-
- public Object getValue() {
- return this.spinner.getValue();
- }
-
- public void setImmediateEditListener(TableCellEditorAdapter.ImmediateEditListener listener) {
- this.immediateEditListener = listener;
- }
-
-
- // ********** public API **********
-
- /**
- * Set the spinner's model.
- */
- public void setModel(SpinnerModel model) {
- this.spinner.setModel(model);
- }
-
- /**
- * Return the renderer's preferred height. This allows you
- * to set the row height to something the spinner will look good in....
- */
- public int preferredHeight() {
- // add in space for the border top and bottom
- return (int) this.spinner.getPreferredSize().getHeight() + 2;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/TableCellEditorAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/TableCellEditorAdapter.java
deleted file mode 100644
index b19c86f08d..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/swing/TableCellEditorAdapter.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.internal.swing;
-
-import java.awt.Component;
-import javax.swing.AbstractCellEditor;
-import javax.swing.JTable;
-import javax.swing.table.TableCellEditor;
-import javax.swing.table.TableCellRenderer;
-
-/**
- * A table cell editor that wraps a table cell renderer.
- */
-public class TableCellEditorAdapter extends AbstractCellEditor implements TableCellEditor {
-
- /** delegate to a renderer */
- private Renderer renderer;
-
-
- // ********** constructors/initialization **********
-
- private TableCellEditorAdapter() {
- super();
- }
-
- /**
- * Construct a cell editor that behaves like the specified renderer.
- */
- public TableCellEditorAdapter(Renderer renderer) {
- this();
- this.initialize(renderer);
- }
-
- protected void initialize(Renderer r) {
- this.renderer = r;
- r.setImmediateEditListener(this.buildImmediateEditListener());
- }
-
- private ImmediateEditListener buildImmediateEditListener() {
- return new ImmediateEditListener() {
- public void immediateEdit() {
- TableCellEditorAdapter.this.stopCellEditing();
- }
- };
- }
-
-
- // ********** CellEditor implementation **********
-
- public Object getCellEditorValue() {
- return this.renderer.getValue();
- }
-
-
- // ********** TableCellEditor implementation **********
-
- public Component getTableCellEditorComponent(JTable table, Object value, boolean selected, int row, int column) {
- return this.renderer.getTableCellRendererComponent(table, value, selected, true, row, column);
- }
-
-
- // ********** Member classes **********************************************
-
- /**
- * This interface defines the methods that must be implemented by a renderer
- * that can be wrapped by a TableCellEditorAdapter.
- */
- public interface Renderer extends TableCellRenderer {
-
- /**
- * Return the current value of the renderer.
- */
- Object getValue();
-
- /**
- * Set the immediate edit listener
- */
- void setImmediateEditListener(ImmediateEditListener listener);
- }
-
-
- public interface ImmediateEditListener {
-
- /**
- * Called when the renderer does an "immediate edit"
- */
- void immediateEdit();
- }
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/Model.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/Model.java
deleted file mode 100644
index 33f2fd2afd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/Model.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model;
-
-import org.eclipse.jpt.utility.model.listener.CollectionChangeListener;
-import org.eclipse.jpt.utility.model.listener.ListChangeListener;
-import org.eclipse.jpt.utility.model.listener.PropertyChangeListener;
-import org.eclipse.jpt.utility.model.listener.StateChangeListener;
-import org.eclipse.jpt.utility.model.listener.TreeChangeListener;
-
-/**
- * Interface to be implemented by models that notify listeners of
- * changes to bound properties, collections, lists, and/or trees.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface Model {
-
- // ********** state change **********
-
- /**
- * Add a listener that listens to all state change events.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addStateChangeListener(StateChangeListener listener);
-
- /**
- * Remove the specified state change listener. If the listener
- * was added more than once, it will be notified one less time
- * after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeStateChangeListener(StateChangeListener listener);
-
-
- // ********** property change **********
-
- /**
- * Add a listener that listens to all property change events,
- * regardless of the property name associated with that event.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addPropertyChangeListener(PropertyChangeListener listener);
-
- /**
- * Add a listener that listens to all property change events with
- * the specified property name.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);
-
- /**
- * Remove a listener that listens to all property change events,
- * regardless of the property name associated with that event.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removePropertyChangeListener(PropertyChangeListener listener);
-
- /**
- * Remove a listener that listens to all property change events,
- * with the specified property name.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);
-
-
- // ********** collection change **********
-
- /**
- * Add a listener that listens to all collection change events,
- * regardless of the collection name associated with that event.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addCollectionChangeListener(CollectionChangeListener listener);
-
- /**
- * Add a listener that listens to all collection change events with
- * the specified collection name.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addCollectionChangeListener(String collectionName, CollectionChangeListener listener);
-
- /**
- * Remove a listener that listens to all collection change events,
- * regardless of the collection name associated with that event.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeCollectionChangeListener(CollectionChangeListener listener);
-
- /**
- * Remove a listener that listens to all collection change events,
- * with the specified collection name.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeCollectionChangeListener(String collectionName, CollectionChangeListener listener);
-
-
- // ********** list change **********
-
- /**
- * Add a listener that listens to all list change events,
- * regardless of the list name associated with that event.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addListChangeListener(ListChangeListener listener);
-
- /**
- * Add a listener that listens to all list change events with
- * the specified list name.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addListChangeListener(String listName, ListChangeListener listener);
-
- /**
- * Remove a listener that listens to all list change events,
- * regardless of the list name associated with that event.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeListChangeListener(ListChangeListener listener);
-
- /**
- * Remove a listener that listens to all list change events,
- * with the specified list name.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeListChangeListener(String listName, ListChangeListener listener);
-
-
- // ********** tree change **********
-
- /**
- * Add a listener that listens to all tree change events,
- * regardless of the tree name associated with that event.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addTreeChangeListener(TreeChangeListener listener);
-
- /**
- * Add a listener that listens to all tree change events with
- * the specified tree name.
- * The same listener may be added more than once and will be called
- * as many times as it is added. The listener cannot be null.
- */
- void addTreeChangeListener(String treeName, TreeChangeListener listener);
-
- /**
- * Remove a listener that listens to all tree change events,
- * regardless of the tree name associated with that event.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeTreeChangeListener(TreeChangeListener listener);
-
- /**
- * Remove a listener that listens to all tree change events,
- * with the specified tree name.
- * If the listener was added more than once, it will be notified one less
- * time after being removed. An exception will be thrown if the
- * listener is null or if the listener was never added.
- */
- void removeTreeChangeListener(String treeName, TreeChangeListener listener);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ChangeEvent.java
deleted file mode 100644
index 5217abbd65..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ChangeEvent.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.event;
-
-import java.util.EventObject;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * Abstract class for all the change events that can be fired by models.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public abstract class ChangeEvent extends EventObject {
-
- private static final long serialVersionUID = 1L;
-
-
- /**
- * Construct a new change event.
- *
- * @param source The object on which the event initially occurred.
- */
- protected ChangeEvent(Model source) {
- super(source);
- }
-
- /**
- * Covariant override.
- */
- @Override
- public Model getSource() {
- return (Model) super.getSource();
- }
-
- /**
- * Return the name of the aspect of the source that changed.
- * May be null if inappropriate.
- */
- public abstract String getAspectName();
-
- /**
- * Return a copy of the event with the specified source
- * replacing the current source.
- */
- public abstract ChangeEvent cloneWithSource(Model newSource);
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.getAspectName());
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/CollectionChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/CollectionChangeEvent.java
deleted file mode 100644
index 386026c786..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/CollectionChangeEvent.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.event;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * A "collection change" event gets delivered whenever a model changes a "bound"
- * or "constrained" collection. A CollectionChangeEvent is sent as an
- * argument to the CollectionChangeListener.
- *
- * Normally a CollectionChangeEvent is accompanied by the collection name and
- * the items that were added to or removed from the changed collection.
- *
- * Design options:
- * - create a collection to wrap a single added or removed item
- * (this is the option we implemented below and in collaborating code)
- * since there is no way to optimize downstream code for
- * single items, we take another performance hit by building
- * a collection each time (@see Collections#singleton(Object))
- * and forcing downstream code to use an iterator every time
- *
- * - fire a separate event for each item added or removed
- * eliminates any potential for optimizations to downstream code
- *
- * - add protocol to support both single items and collections
- * adds conditional logic to downstream code
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class CollectionChangeEvent extends ChangeEvent {
-
- /** Name of the collection that changed. */
- private final String collectionName;
-
- /** The items that were added to or removed from the collection. May be empty, if not known. */
- private final Collection<?> items;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a new collection change event.
- *
- * @param source The object on which the event initially occurred.
- * @param collectionName The programmatic name of the collection that was changed.
- * @param items The items that were added to or removed from the collection.
- */
- public CollectionChangeEvent(Model source, String collectionName, Collection<?> items) {
- super(source);
- if ((collectionName == null) || (items == null)) {
- throw new NullPointerException();
- }
- this.collectionName = collectionName;
- this.items = Collections.unmodifiableCollection(items);
- }
-
- /**
- * Construct a new collection change event.
- *
- * @param source The object on which the event initially occurred.
- * @param collectionName The programmatic name of the collection that was changed.
- */
- public CollectionChangeEvent(Model source, String collectionName) {
- this(source, collectionName, Collections.emptySet());
- }
-
-
- // ********** standard state **********
-
- /**
- * Return the programmatic name of the collection that was changed.
- */
- public String getCollectionName() {
- return this.collectionName;
- }
-
- @Override
- public String getAspectName() {
- return this.collectionName;
- }
-
- /**
- * Return an iterator on the items that were added to or
- * removed from the collection.
- * May be empty if inappropriate or unknown.
- */
- public Iterator<?> items() {
- return this.items.iterator();
- }
-
- /**
- * Return the number of items that were added to or
- * removed from the collection.
- * May be 0 if inappropriate or unknown.
- */
- public int itemsSize() {
- return this.items.size();
- }
-
-
- // ********** cloning **********
-
- /**
- * Return a copy of the event with the specified source
- * replacing the current source.
- */
- @Override
- public CollectionChangeEvent cloneWithSource(Model newSource) {
- return new CollectionChangeEvent(newSource, this.collectionName, this.items);
- }
-
- /**
- * Return a copy of the event with the specified source and collection name
- * replacing the current source and collection name.
- */
- public CollectionChangeEvent cloneWithSource(Model newSource, String newCollectionName) {
- return new CollectionChangeEvent(newSource, newCollectionName, this.items);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ListChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ListChangeEvent.java
deleted file mode 100644
index 9ec18ae194..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/ListChangeEvent.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.event;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * A "list change" event gets delivered whenever a model changes a "bound"
- * or "constrained" list. A ListChangeEvent is sent as an
- * argument to the ListChangeListener.
- *
- * Normally a ListChangeEvent is accompanied by the list name,
- * the items that were added to or removed from the changed list,
- * and the index of where the items are or were in the list.
- *
- * Design options:
- * - create a list to wrap a single added or removed item
- * (this is the option we implemented below and in collaborating code)
- * since there is no way to optimize downstream code for
- * single items, we take another performance hit by building
- * a list each time (@see Collections#singletonList(Object))
- * and forcing downstream code to use a list iterator every time
- *
- * - fire a separate event for each item added or removed
- * eliminates any potential for optimizations to downstream code
- *
- * - add protocol to support both single items and collections
- * adds conditional logic to downstream code
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class ListChangeEvent extends ChangeEvent {
-
- /**
- * Name of the list that changed.
- */
- private final String listName;
-
- /**
- * The index at which the items were added, removed, or replaced.
- * In the case of "moved" items, this will be the "target" index.
- * May be -1, if not known.
- */
- private final int index;
-
- /**
- * The items that were added to or removed from the list. In the case of
- * "replaced" items, these are the new items in the list.
- * In the case of "moved" items, this will be empty.
- * May be empty, if not known.
- */
- private final List<?> items;
-
- /**
- * The items in the list that were replaced by the items listed above,
- * in #items. May be empty, if not known.
- */
- private final List<?> replacedItems;
-
- /**
- * In the case of "moved" items, this will be the "source" index.
- * May be -1, if not known.
- */
- private final int sourceIndex;
-
- /**
- * In the case of "moved" items, this will be the number of items moved.
- * May be -1, if not known.
- */
- private final int moveLength;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- protected ListChangeEvent(Model source, String listName, int index, List<?> items, List<?> replacedItems, int sourceIndex, int moveLength) {
- super(source);
- if ((listName == null) || (items == null) || (replacedItems == null)) {
- throw new NullPointerException();
- }
- this.listName = listName;
- this.index = index;
- this.items = Collections.unmodifiableList(items);
- this.replacedItems = Collections.unmodifiableList(replacedItems);
- this.sourceIndex = sourceIndex;
- this.moveLength = moveLength;
- }
-
- /**
- * Construct a new list change event for a list of replaced items.
- *
- * @param source The object on which the event initially occurred.
- * @param listName The programmatic name of the list that was changed.
- * @param index The index at which the items in the list were replaced.
- * @param items The new items in the list.
- * @param replacedItems The items in the list that were replaced.
- */
- public ListChangeEvent(Model source, String listName, int index, List<?> items, List<?> replacedItems) {
- this(source, listName, index, items, replacedItems, -1, -1);
- }
-
- /**
- * Construct a new list change event for a list of added or removed items.
- *
- * @param source The object on which the event initially occurred.
- * @param listName The programmatic name of the list that was changed.
- * @param index The index at which the items were added to or removed from the list.
- * @param items The items that were added to or removed from the list.
- */
- public ListChangeEvent(Model source, String listName, int index, List<?> items) {
- this(source, listName, index, items, Collections.emptyList(), -1, -1);
- }
-
- /**
- * Construct a new list change event for a list of moved items.
- *
- * @param source The object on which the event initially occurred.
- * @param listName The programmatic name of the list that was changed.
- * @param targetIndex The index to which the items were moved.
- * @param sourceIndex The index from which the items were moved.
- */
- public ListChangeEvent(Model source, String listName, int targetIndex, int sourceIndex, int length) {
- this(source, listName, targetIndex, Collections.emptyList(), Collections.emptyList(), sourceIndex, length);
- }
-
- /**
- * Construct a new list change event.
- *
- * @param source The object on which the event initially occurred.
- * @param listName The programmatic name of the list that was changed.
- */
- public ListChangeEvent(Model source, String listName) {
- this(source, listName, -1, Collections.emptyList(), Collections.emptyList(), -1, -1);
- }
-
-
- // ********** standard state **********
-
- /**
- * Return the programmatic name of the list that was changed.
- */
- public String getListName() {
- return this.listName;
- }
-
- @Override
- public String getAspectName() {
- return this.listName;
- }
-
- /**
- * Return the index at which the items were added to, removed from,
- * or replaced in the list.
- * In the case of "moved" items, this will be the "target" index.
- * May be -1 if inappropriate or unknown.
- */
- public int getIndex() {
- return this.index;
- }
-
- /**
- * Return a list iterator on the items that were added to or
- * removed from the list. In the case of "replaced" items, these
- * are the new items in the list.
- * May be empty if inappropriate or unknown.
- */
- public ListIterator<?> items() {
- return this.items.listIterator();
- }
-
- /**
- * Return the number of items that were added to,
- * removed from, or replaced in the list.
- * May be 0 if inappropriate or unknown.
- */
- public int itemsSize() {
- return this.items.size();
- }
-
-
- // ********** replace **********
-
- /**
- * Return a list iterator on the items in the list that were replaced.
- * May be empty if inappropriate or unknown.
- */
- public ListIterator<?> replacedItems() {
- return this.replacedItems.listIterator();
- }
-
-
- // ********** move **********
-
- /**
- * In the case of "moved" items, this will be the "target" index.
- * May be -1 if inappropriate or unknown.
- */
- public int getTargetIndex() {
- return this.index;
- }
-
- /**
- * In the case of "moved" items, this will be the "source" index.
- * May be -1 if inappropriate or unknown.
- */
- public int getSourceIndex() {
- return this.sourceIndex;
- }
-
- /**
- * In the case of "moved" items, this will be the number of items moved.
- * May be -1 if inappropriate or unknown.
- */
- public int getMoveLength() {
- return this.moveLength;
- }
-
-
- // ********** cloning **********
-
- /**
- * Return a copy of the event with the specified source
- * replacing the current source.
- */
- @Override
- public ListChangeEvent cloneWithSource(Model newSource) {
- return new ListChangeEvent(newSource, this.listName, this.index, this.items, this.replacedItems, this.sourceIndex, this.moveLength);
- }
-
- /**
- * Return a copy of the event with the specified source and list name
- * replacing the current source and list name.
- */
- public ListChangeEvent cloneWithSource(Model newSource, String newListName) {
- return new ListChangeEvent(newSource, newListName, this.index, this.items, this.replacedItems, this.sourceIndex, this.moveLength);
- }
-
- /**
- * Return a copy of the event with the specified source and list name
- * replacing the current source and list name and displacing
- * the index by the specified amount.
- */
- public ListChangeEvent cloneWithSource(Model newSource, String newListName, int offset) {
- return new ListChangeEvent(newSource, newListName, this.index + offset, this.items, this.replacedItems, this.sourceIndex + offset, this.moveLength);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/PropertyChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/PropertyChangeEvent.java
deleted file mode 100644
index ee2fa2f8b2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/PropertyChangeEvent.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.event;
-
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * A "property change" event gets delivered whenever a model changes a "bound"
- * or "constrained" property. A PropertyChangeEvent is sent as an
- * argument to the PropertyChangeListener.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class PropertyChangeEvent extends ChangeEvent {
-
- /** Name of the property that changed. */
- private final String propertyName;
-
- /** The property's old value, before the change. */
- private final Object oldValue;
-
- /** The property's new value, after the change. */
- private final Object newValue;
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a new property change event.
- *
- * @param source The object on which the event initially occurred.
- * @param propertyName The programmatic name of the property that was changed.
- * @param oldValue The old value of the property.
- * @param newValue The new value of the property.
- */
- public PropertyChangeEvent(Model source, String propertyName, Object oldValue, Object newValue) {
- super(source);
- if (propertyName == null) {
- throw new NullPointerException();
- }
- this.propertyName = propertyName;
- this.oldValue = oldValue;
- this.newValue = newValue;
- }
-
-
- // ********** standard state **********
-
- /**
- * Return the programmatic name of the property that was changed.
- */
- public String getPropertyName() {
- return this.propertyName;
- }
-
- @Override
- public String getAspectName() {
- return this.propertyName;
- }
-
- /**
- * Return the old value of the property.
- */
- public Object getOldValue() {
- return this.oldValue;
- }
-
- /**
- * Return the new value of the property.
- */
- public Object getNewValue() {
- return this.newValue;
- }
-
-
- // ********** cloning **********
-
- @Override
- public PropertyChangeEvent cloneWithSource(Model newSource) {
- return new PropertyChangeEvent(newSource, this.propertyName, this.oldValue, this.newValue);
- }
-
- /**
- * Return a copy of the event with the specified source
- * replacing the current source and the property name.
- */
- public PropertyChangeEvent cloneWithSource(Model newSource, String newPropertyName) {
- return new PropertyChangeEvent(newSource, newPropertyName, this.oldValue, this.newValue);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/StateChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/StateChangeEvent.java
deleted file mode 100644
index 52e3690e69..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/StateChangeEvent.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.event;
-
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * A generic "state change" event gets delivered whenever a model changes to
- * such extent that it cannot be delineated all aspects of it that have changed.
- * A StateChangeEvent is sent as an argument to the StateChangeListener.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class StateChangeEvent extends ChangeEvent {
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a new state change event.
- *
- * @param source The object on which the event initially occurred.
- */
- public StateChangeEvent(Model source) {
- super(source);
- }
-
-
- // ********** standard state **********
-
- @Override
- public String getAspectName() {
- return null; // the point of the event is that the name is unknown...
- }
-
-
- // ********** cloning **********
-
- @Override
- public StateChangeEvent cloneWithSource(Model newSource) {
- return new StateChangeEvent(newSource);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/TreeChangeEvent.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/TreeChangeEvent.java
deleted file mode 100644
index 2272020490..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/event/TreeChangeEvent.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.event;
-
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * A "tree change" event gets delivered whenever a model changes a "bound"
- * or "constrained" tree. A TreeChangeEvent is sent as an
- * argument to the TreeChangeListener.
- *
- * Normally a TreeChangeEvent is accompanied by the tree name and a path
- * to the part of the tree that was changed.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class TreeChangeEvent extends ChangeEvent {
-
- /** Name of the tree that changed. */
- private final String treeName;
-
- /**
- * Path to the parent of the part of the tree that was changed.
- * May be empty, if not known or if the entire tree changed.
- */
- protected final Object[] path;
-
- private static final Object[] EMPTY_PATH = new Object[0];
-
- private static final long serialVersionUID = 1L;
-
-
- // ********** constructors **********
-
- /**
- * Construct a new tree change event.
- *
- * @param source The object on which the event initially occurred.
- * @param treeName The programmatic name of the tree that was changed.
- * @param path The path to the part of the tree that was changed.
- */
- public TreeChangeEvent(Model source, String treeName, Object[] path) {
- super(source);
- if ((treeName == null) || (path == null)) {
- throw new NullPointerException();
- }
- this.treeName = treeName;
- this.path = path;
- }
-
- /**
- * Construct a new tree change event.
- *
- * @param source The object on which the event initially occurred.
- * @param treeName The programmatic name of the tree that was changed.
- */
- public TreeChangeEvent(Model source, String treeName) {
- this(source, treeName, EMPTY_PATH);
- }
-
-
- // ********** standard state **********
-
- /**
- * Return the programmatic name of the tree that was changed.
- */
- public String getTreeName() {
- return this.treeName;
- }
-
- @Override
- public String getAspectName() {
- return this.treeName;
- }
-
- /**
- * Return the path to the part of the tree that was changed.
- * May be empty, if not known.
- */
- public Object[] getPath() {
- return this.path;
- }
-
-
- // ********** cloning **********
-
- @Override
- public TreeChangeEvent cloneWithSource(Model newSource) {
- return new TreeChangeEvent(newSource, this.treeName, this.path);
- }
-
- /**
- * Return a copy of the event with the specified source
- * replacing the current source and the tree name.
- */
- public TreeChangeEvent cloneWithSource(Model newSource, String newTreeName) {
- return new TreeChangeEvent(newSource, newTreeName, this.path);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ChangeListener.java
deleted file mode 100644
index d29a7a7de2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ChangeListener.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import java.util.EventListener;
-
-/**
- * Marker interface.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface ChangeListener extends EventListener {
- // nothing for now
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeAdapter.java
deleted file mode 100644
index 88b1359e16..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeAdapter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-
-/**
- * Convenience implementation of CollectionChangeListener.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class CollectionChangeAdapter implements CollectionChangeListener {
-
- /**
- * Default constructor.
- */
- public CollectionChangeAdapter() {
- super();
- }
-
- public void itemsAdded(CollectionChangeEvent event) {
- // do nothing
- }
-
- public void itemsRemoved(CollectionChangeEvent event) {
- // do nothing
- }
-
- public void collectionCleared(CollectionChangeEvent event) {
- // do nothing
- }
-
- public void collectionChanged(CollectionChangeEvent event) {
- // do nothing
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeListener.java
deleted file mode 100644
index 210388b923..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/CollectionChangeListener.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-
-/**
- * A "collection change" event gets fired whenever a model changes a "bound"
- * collection. You can register a CollectionChangeListener with a source
- * model so as to be notified of any bound collection updates.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface CollectionChangeListener extends ChangeListener {
-
- /**
- * This method gets called when items are added to a bound collection.
- *
- * @param event A CollectionChangeEvent describing the event source,
- * the collection that changed, and the items that were added.
- */
- void itemsAdded(CollectionChangeEvent event);
-
- /**
- * This method gets called when items are removed from a bound collection.
- *
- * @param event A CollectionChangeEvent describing the event source,
- * the collection that changed, and the items that were removed.
- */
- void itemsRemoved(CollectionChangeEvent event);
-
- /**
- * This method gets called when a bound collection is cleared.
- *
- * @param event A CollectionChangeEvent describing the event source
- * and the collection that changed.
- */
- void collectionCleared(CollectionChangeEvent event);
-
- /**
- * This method gets called when a bound collection is changed in a manner
- * that is not easily characterized by the other methods in this interface.
- *
- * @param event A CollectionChangeEvent describing the event source
- * and the collection that changed.
- */
- void collectionChanged(CollectionChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeAdapter.java
deleted file mode 100644
index 052abc5cf4..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeAdapter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-
-/**
- * Convenience implementation of ListChangeListener.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class ListChangeAdapter implements ListChangeListener {
-
- /**
- * Default constructor.
- */
- public ListChangeAdapter() {
- super();
- }
-
- public void itemsAdded(ListChangeEvent event) {
- // do nothing
- }
-
- public void itemsRemoved(ListChangeEvent event) {
- // do nothing
- }
-
- public void itemsReplaced(ListChangeEvent event) {
- // do nothing
- }
-
- public void itemsMoved(ListChangeEvent event) {
- // do nothing
- }
-
- public void listCleared(ListChangeEvent event) {
- // do nothing
- }
-
- public void listChanged(ListChangeEvent event) {
- // do nothing
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeListener.java
deleted file mode 100644
index 74eab3a002..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ListChangeListener.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-
-/**
- * A "list change" event gets fired whenever a model changes a "bound"
- * list. You can register a ListChangeListener with a source
- * model so as to be notified of any bound list updates.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface ListChangeListener extends ChangeListener {
-
- /**
- * This method gets called when items are added to a bound list.
- *
- * @param event A ListChangeEvent describing the event source,
- * the list that changed, the items that were added, and the index
- * at which the items were added.
- */
- void itemsAdded(ListChangeEvent event);
-
- /**
- * This method gets called when items are removed from a bound list.
- *
- * @param event A ListChangeEvent describing the event source,
- * the list that changed, the items that were removed, and the index
- * at which the items were removed.
- */
- void itemsRemoved(ListChangeEvent event);
-
- /**
- * This method gets called when items in a bound list are replaced.
- *
- * @param event A ListChangeEvent describing the event source,
- * the list that changed, the items that were added, the items that were
- * replaced, and the index at which the items were replaced.
- */
- void itemsReplaced(ListChangeEvent event);
-
- /**
- * This method gets called when items in a bound list are moved.
- *
- * @param event A ListChangeEvent describing the event source,
- * the list that changed, and the indices of where items were moved
- * from and to.
- */
- void itemsMoved(ListChangeEvent event);
-
- /**
- * This method gets called when a bound list is cleared.
- *
- * @param event A ListChangeEvent object describing the event source
- * and the list that changed.
- */
- void listCleared(ListChangeEvent event);
-
- /**
- * This method gets called when a bound list is changed in a manner
- * that is not easily characterized by the other methods in this interface.
- *
- * @param event A ListChangeEvent object describing the event source
- * and the list that changed.
- */
- void listChanged(ListChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/MultiMethodReflectiveChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/MultiMethodReflectiveChangeListener.java
deleted file mode 100644
index 9b69de5195..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/MultiMethodReflectiveChangeListener.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import java.lang.reflect.Method;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-
-/**
- * This class is used by ReflectiveChangeListener when the requested listener
- * needs to implement multiple methods (i.e. CollectionChangeListener,
- * ListChangeListener, or TreeChangeListener).
- */
-class MultiMethodReflectiveChangeListener
- extends ReflectiveChangeListener
- implements CollectionChangeListener, ListChangeListener, TreeChangeListener
-{
- /** the methods we will invoke on the target object */
- private final Method addMethod;
- private final Method removeMethod;
- private final Method replaceMethod; // this can be null
- private final Method moveMethod; // this can be null
- private final Method clearMethod;
- private final Method changeMethod;
-
-
- /**
- * The "replace" and "move" methods are optional.
- */
- MultiMethodReflectiveChangeListener(Object target, Method addMethod, Method removeMethod, Method replaceMethod, Method moveMethod, Method clearMethod, Method changeMethod) {
- super(target);
- this.addMethod = addMethod;
- this.removeMethod = removeMethod;
- this.replaceMethod = replaceMethod;
- this.moveMethod = moveMethod;
- this.clearMethod = clearMethod;
- this.changeMethod = changeMethod;
- }
-
- /**
- * No "replace" or "move" methods.
- */
- MultiMethodReflectiveChangeListener(Object target, Method addMethod, Method removeMethod, Method clearMethod, Method changeMethod) {
- this(target, addMethod, removeMethod, null, null, clearMethod, changeMethod);
- }
-
-
- // ********** CollectionChangeListener implementation **********
-
- private void invoke(Method method, CollectionChangeEvent event) {
- if (method.getParameterTypes().length == 0) {
- ClassTools.executeMethod(method, this.target, EMPTY_COLLECTION_CHANGE_EVENT_ARRAY);
- } else {
- ClassTools.executeMethod(method, this.target, new CollectionChangeEvent[] {event});
- }
- }
-
- public void itemsAdded(CollectionChangeEvent event) {
- this.invoke(this.addMethod, event);
- }
-
- public void itemsRemoved(CollectionChangeEvent event) {
- this.invoke(this.removeMethod, event);
- }
-
- public void collectionCleared(CollectionChangeEvent event) {
- this.invoke(this.clearMethod, event);
- }
-
- public void collectionChanged(CollectionChangeEvent event) {
- this.invoke(this.changeMethod, event);
- }
-
-
- // ********** ListChangeListener implementation **********
-
- private void invoke(Method method, ListChangeEvent event) {
- if (method.getParameterTypes().length == 0) {
- ClassTools.executeMethod(method, this.target, EMPTY_LIST_CHANGE_EVENT_ARRAY);
- } else {
- ClassTools.executeMethod(method, this.target, new ListChangeEvent[] {event});
- }
- }
-
- public void itemsAdded(ListChangeEvent event) {
- this.invoke(this.addMethod, event);
- }
-
- public void itemsRemoved(ListChangeEvent event) {
- this.invoke(this.removeMethod, event);
- }
-
- public void itemsReplaced(ListChangeEvent event) {
- this.invoke(this.replaceMethod, event);
- }
-
- public void itemsMoved(ListChangeEvent event) {
- this.invoke(this.moveMethod, event);
- }
-
- public void listCleared(ListChangeEvent event) {
- this.invoke(this.clearMethod, event);
- }
-
- public void listChanged(ListChangeEvent event) {
- this.invoke(this.changeMethod, event);
- }
-
-
- // ********** TreeChangeListener implementation **********
-
- private void invoke(Method method, TreeChangeEvent event) {
- if (method.getParameterTypes().length == 0) {
- ClassTools.executeMethod(method, this.target, EMPTY_TREE_CHANGE_EVENT_ARRAY);
- } else {
- ClassTools.executeMethod(method, this.target, new TreeChangeEvent[] {event});
- }
- }
-
- public void nodeAdded(TreeChangeEvent event) {
- this.invoke(this.addMethod, event);
- }
-
- public void nodeRemoved(TreeChangeEvent event) {
- this.invoke(this.removeMethod, event);
- }
-
- public void treeCleared(TreeChangeEvent event) {
- this.invoke(this.clearMethod, event);
- }
-
- public void treeChanged(TreeChangeEvent event) {
- this.invoke(this.changeMethod, event);
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/PropertyChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/PropertyChangeListener.java
deleted file mode 100644
index f76bed7d39..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/PropertyChangeListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-
-/**
- * A "property change" event gets fired whenever a model changes a "bound"
- * property. You can register a PropertyChangeListener with a source
- * model so as to be notified of any bound property updates.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface PropertyChangeListener extends ChangeListener {
-
- /**
- * This method gets called when a model has changed a bound property.
- *
- * @param event A StateChangeEvent describing the event source
- * and the property's old and new values.
- */
- void propertyChanged(PropertyChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ReflectiveChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ReflectiveChangeListener.java
deleted file mode 100644
index 0cab7d7cbd..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/ReflectiveChangeListener.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import java.lang.reflect.Method;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.model.event.ChangeEvent;
-import org.eclipse.jpt.utility.model.event.CollectionChangeEvent;
-import org.eclipse.jpt.utility.model.event.ListChangeEvent;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-
-/**
- * This factory builds listeners that reflectively forward ChangeEvents.
- * If you are worried about having too many little classes that have to be
- * loaded and maintained by the class loader, you can use one of these.
- * Of course, this comes with the additional overhead of reflection....
- * Also note that the validity of the method name is not checked at compile
- * time, but at runtime; although we *do* check the method as soon as the
- * listener is instantiated.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public abstract class ReflectiveChangeListener {
-
- /** the target object on which we will invoke the method */
- protected final Object target;
-
-
- protected static final Class<StateChangeEvent> STATE_CHANGE_EVENT_CLASS = StateChangeEvent.class;
- @SuppressWarnings("unchecked")
- protected static final Class<StateChangeEvent>[] STATE_CHANGE_EVENT_CLASS_ARRAY = new Class[] {STATE_CHANGE_EVENT_CLASS};
- protected static final StateChangeEvent[] EMPTY_STATE_CHANGE_EVENT_ARRAY = new StateChangeEvent[0];
-
- protected static final Class<PropertyChangeEvent> PROPERTY_CHANGE_EVENT_CLASS = PropertyChangeEvent.class;
- @SuppressWarnings("unchecked")
- protected static final Class<PropertyChangeEvent>[] PROPERTY_CHANGE_EVENT_CLASS_ARRAY = new Class[] {PROPERTY_CHANGE_EVENT_CLASS};
- protected static final PropertyChangeEvent[] EMPTY_PROPERTY_CHANGE_EVENT_ARRAY = new PropertyChangeEvent[0];
-
- protected static final Class<CollectionChangeEvent> COLLECTION_CHANGE_EVENT_CLASS = CollectionChangeEvent.class;
- @SuppressWarnings("unchecked")
- protected static final Class<CollectionChangeEvent>[] COLLECTION_CHANGE_EVENT_CLASS_ARRAY = new Class[] {COLLECTION_CHANGE_EVENT_CLASS};
- protected static final CollectionChangeEvent[] EMPTY_COLLECTION_CHANGE_EVENT_ARRAY = new CollectionChangeEvent[0];
-
- protected static final Class<ListChangeEvent> LIST_CHANGE_EVENT_CLASS = ListChangeEvent.class;
- @SuppressWarnings("unchecked")
- protected static final Class<ListChangeEvent>[] LIST_CHANGE_EVENT_CLASS_ARRAY = new Class[] {LIST_CHANGE_EVENT_CLASS};
- protected static final ListChangeEvent[] EMPTY_LIST_CHANGE_EVENT_ARRAY = new ListChangeEvent[0];
-
- protected static final Class<TreeChangeEvent> TREE_CHANGE_EVENT_CLASS = TreeChangeEvent.class;
- @SuppressWarnings("unchecked")
- protected static final Class<TreeChangeEvent>[] TREE_CHANGE_EVENT_CLASS_ARRAY = new Class[] {TREE_CHANGE_EVENT_CLASS};
- protected static final TreeChangeEvent[] EMPTY_TREE_CHANGE_EVENT_ARRAY = new TreeChangeEvent[0];
-
-
-
- // ********** helper methods **********
-
- /**
- * Find and return a method implemented by the target that can be invoked
- * reflectively when a change event occurs.
- */
- private static Method findChangeListenerMethod(Object target, String methodName, Class<? extends ChangeEvent>[] eventClassArray) {
- Method method;
- try {
- method = ClassTools.method(target, methodName, eventClassArray);
- } catch (NoSuchMethodException ex1) {
- try {
- method = ClassTools.method(target, methodName);
- } catch (NoSuchMethodException ex2) {
- throw new RuntimeException(ex2); // "checked" exceptions bite
- }
- }
- return method;
- }
-
- /**
- * Check whether the specified method is suitable for being invoked when a
- * change event has occurred. Throw an exception if it is not suitable.
- */
- private static void checkChangeListenerMethod(Method method, Class<? extends ChangeEvent> eventClass) {
- Class<?>[] parmTypes = method.getParameterTypes();
- int parmTypesLength = parmTypes.length;
- if (parmTypesLength == 0) {
- return;
- }
- if ((parmTypesLength == 1) && parmTypes[0].isAssignableFrom(eventClass)) {
- return;
- }
- throw new IllegalArgumentException(method.toString());
- }
-
-
- // ********** factory methods: StateChangeListener **********
-
- /**
- * Construct a state change listener that will invoke the specified method
- * on the specified target.
- */
- public static StateChangeListener buildStateChangeListener(Object target, Method method) {
- checkChangeListenerMethod(method, STATE_CHANGE_EVENT_CLASS);
- return new SingleMethodReflectiveChangeListener(target, method);
- }
-
- /**
- * Construct a state change listener that will invoke the specified method
- * on the specified target. If a single-argument method with the specified
- * name and appropriate argument is found, it will be invoked; otherwise,
- * a zero-argument method with the specified name will be invoked.
- */
- public static StateChangeListener buildStateChangeListener(Object target, String methodName) {
- return buildStateChangeListener(target, findChangeListenerMethod(target, methodName, STATE_CHANGE_EVENT_CLASS_ARRAY));
- }
-
-
- // ********** factory methods: PropertyChangeListener **********
-
- /**
- * Construct a property change listener that will invoke the specified method
- * on the specified target.
- */
- public static PropertyChangeListener buildPropertyChangeListener(Object target, Method method) {
- checkChangeListenerMethod(method, PROPERTY_CHANGE_EVENT_CLASS);
- return new SingleMethodReflectiveChangeListener(target, method);
- }
-
- /**
- * Construct a property change listener that will invoke the specified method
- * on the specified target. If a single-argument method with the specified
- * name and appropriate argument is found, it will be invoked; otherwise,
- * a zero-argument method with the specified name will be invoked.
- */
- public static PropertyChangeListener buildPropertyChangeListener(Object target, String methodName) {
- return buildPropertyChangeListener(target, findChangeListenerMethod(target, methodName, PROPERTY_CHANGE_EVENT_CLASS_ARRAY));
- }
-
-
- // ********** factory methods: CollectionChangeListener **********
-
- /**
- * Construct a collection change listener that will invoke the specified methods
- * on the specified target.
- */
- public static CollectionChangeListener buildCollectionChangeListener(Object target, Method addMethod, Method removeMethod, Method clearMethod, Method changeMethod) {
- checkChangeListenerMethod(addMethod, COLLECTION_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(removeMethod, COLLECTION_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(clearMethod, COLLECTION_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(changeMethod, COLLECTION_CHANGE_EVENT_CLASS);
- return new MultiMethodReflectiveChangeListener(target, addMethod, removeMethod, clearMethod, changeMethod);
- }
-
- /**
- * Construct a collection change listener that will invoke the specified method
- * on the specified target for any change event.
- */
- public static CollectionChangeListener buildCollectionChangeListener(Object target, Method method) {
- return buildCollectionChangeListener(target, method, method, method, method);
- }
-
- /**
- * Construct a collection change listener that will invoke the specified methods
- * on the specified target for change events. If a single-argument method
- * with the specified name and appropriate argument is found, it will be invoked;
- * otherwise, a zero-argument method with the specified name will be invoked.
- */
- public static CollectionChangeListener buildCollectionChangeListener(Object target, String addMethodName, String removeMethodName, String clearMethodName, String changeMethodName) {
- return buildCollectionChangeListener(
- target,
- findChangeListenerMethod(target, addMethodName, COLLECTION_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, removeMethodName, COLLECTION_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, clearMethodName, COLLECTION_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, changeMethodName, COLLECTION_CHANGE_EVENT_CLASS_ARRAY)
- );
- }
-
- /**
- * Construct a collection change listener that will invoke the specified method
- * on the specified target for any change event. If a single-argument method
- * with the specified name and appropriate argument is found, it will be invoked;
- * otherwise, a zero-argument method with the specified name will be invoked.
- */
- public static CollectionChangeListener buildCollectionChangeListener(Object target, String methodName) {
- return buildCollectionChangeListener(target, findChangeListenerMethod(target, methodName, COLLECTION_CHANGE_EVENT_CLASS_ARRAY));
- }
-
-
- // ********** factory methods: ListChangeListener **********
-
- /**
- * Construct a list change listener that will invoke the specified methods
- * on the specified target.
- */
- public static ListChangeListener buildListChangeListener(Object target, Method addMethod, Method removeMethod, Method replaceMethod, Method moveMethod, Method clearMethod, Method changeMethod) {
- checkChangeListenerMethod(addMethod, LIST_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(removeMethod, LIST_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(replaceMethod, LIST_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(moveMethod, LIST_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(clearMethod, LIST_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(changeMethod, LIST_CHANGE_EVENT_CLASS);
- return new MultiMethodReflectiveChangeListener(target, addMethod, removeMethod, replaceMethod, moveMethod, clearMethod, changeMethod);
- }
-
- /**
- * Construct a list change listener that will invoke the specified method
- * on the specified target for any change event.
- */
- public static ListChangeListener buildListChangeListener(Object target, Method method) {
- return buildListChangeListener(target, method, method, method, method, method, method);
- }
-
- /**
- * Construct a list change listener that will invoke the specified methods
- * on the specified target for change events. If a single-argument method
- * with the specified name and appropriate argument is found, it will be invoked;
- * otherwise, a zero-argument method with the specified name will be invoked.
- */
- public static ListChangeListener buildListChangeListener(Object target, String addMethodName, String removeMethodName, String replaceMethodName, String moveMethodName, String clearMethodName, String changeMethodName) {
- return buildListChangeListener(
- target,
- findChangeListenerMethod(target, addMethodName, LIST_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, removeMethodName, LIST_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, replaceMethodName, LIST_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, moveMethodName, LIST_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, clearMethodName, LIST_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, changeMethodName, LIST_CHANGE_EVENT_CLASS_ARRAY)
- );
- }
-
- /**
- * Construct a list change listener that will invoke the specified method
- * on the specified target for any change event. If a single-argument method
- * with the specified name and appropriate argument is found, it will be invoked;
- * otherwise, a zero-argument method with the specified name will be invoked.
- */
- public static ListChangeListener buildListChangeListener(Object target, String methodName) {
- return buildListChangeListener(target, findChangeListenerMethod(target, methodName, LIST_CHANGE_EVENT_CLASS_ARRAY));
- }
-
-
- // ********** factory methods: TreeChangeListener **********
-
- /**
- * Construct a tree change listener that will invoke the specified methods
- * on the specified target.
- */
- public static TreeChangeListener buildTreeChangeListener(Object target, Method addMethod, Method removeMethod, Method clearMethod, Method changeMethod) {
- checkChangeListenerMethod(addMethod, TREE_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(removeMethod, TREE_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(clearMethod, TREE_CHANGE_EVENT_CLASS);
- checkChangeListenerMethod(changeMethod, TREE_CHANGE_EVENT_CLASS);
- return new MultiMethodReflectiveChangeListener(target, addMethod, removeMethod, clearMethod, changeMethod);
- }
-
- /**
- * Construct a tree change listener that will invoke the specified method
- * on the specified target for any change event.
- */
- public static TreeChangeListener buildTreeChangeListener(Object target, Method method) {
- return buildTreeChangeListener(target, method, method, method, method);
- }
-
- /**
- * Construct a tree change listener that will invoke the specified methods
- * on the specified target for change events. If a single-argument method
- * with the specified name and appropriate argument is found, it will be invoked;
- * otherwise, a zero-argument method with the specified name will be invoked.
- */
- public static TreeChangeListener buildTreeChangeListener(Object target, String addMethodName, String removeMethodName, String clearMethodName, String changeMethodName) {
- return buildTreeChangeListener(
- target,
- findChangeListenerMethod(target, addMethodName, TREE_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, removeMethodName, TREE_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, clearMethodName, TREE_CHANGE_EVENT_CLASS_ARRAY),
- findChangeListenerMethod(target, changeMethodName, TREE_CHANGE_EVENT_CLASS_ARRAY)
- );
- }
-
- /**
- * Construct a tree change listener that will invoke the specified method
- * on the specified target for any change event. If a single-argument method
- * with the specified name and appropriate argument is found, it will be invoked;
- * otherwise, a zero-argument method with the specified name will be invoked.
- */
- public static TreeChangeListener buildTreeChangeListener(Object target, String methodName) {
- return buildTreeChangeListener(target, findChangeListenerMethod(target, methodName, TREE_CHANGE_EVENT_CLASS_ARRAY));
- }
-
-
- // ********** constructor **********
-
- /**
- * Construct a listener that will invoke the specified method
- * on the specified target.
- */
- protected ReflectiveChangeListener(Object target) {
- super();
- this.target = target;
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/SingleMethodReflectiveChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/SingleMethodReflectiveChangeListener.java
deleted file mode 100644
index ba7ea243e2..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/SingleMethodReflectiveChangeListener.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import java.lang.reflect.Method;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.model.event.PropertyChangeEvent;
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-
-/**
- * This class is used by ReflectiveChangeListener when the requested listener
- * need only implement a single method (i.e. StateChangeListener or
- * PropertyChangeListener).
- */
-class SingleMethodReflectiveChangeListener
- extends ReflectiveChangeListener
- implements StateChangeListener, PropertyChangeListener
-{
-
- /** the method we will invoke on the target object */
- private final Method method;
- /** cache the number of arguments */
- private final boolean methodIsZeroArgument;
-
- SingleMethodReflectiveChangeListener(Object target, Method method) {
- super(target);
- this.method = method;
- this.methodIsZeroArgument = method.getParameterTypes().length == 0;
- }
-
-
- // ********** StateChangeListener implementation **********
-
- public void stateChanged(StateChangeEvent event) {
- if (this.methodIsZeroArgument) {
- ClassTools.executeMethod(this.method, this.target, EMPTY_STATE_CHANGE_EVENT_ARRAY);
- } else {
- ClassTools.executeMethod(this.method, this.target, new StateChangeEvent[] {event});
- }
- }
-
-
- // ********** PropertyChangeListener implementation **********
-
- public void propertyChanged(PropertyChangeEvent event) {
- if (this.methodIsZeroArgument) {
- ClassTools.executeMethod(this.method, this.target, EMPTY_PROPERTY_CHANGE_EVENT_ARRAY);
- } else {
- ClassTools.executeMethod(this.method, this.target, new PropertyChangeEvent[] {event});
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/StateChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/StateChangeListener.java
deleted file mode 100644
index 1ce6ba5d69..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/StateChangeListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.StateChangeEvent;
-
-/**
- * A generic "state change" event gets delivered whenever a model changes to
- * such extent that it cannot be delineated all aspects of it that have changed.
- * You can register a StateChangeListener with a source model so as to be notified
- * of any such changes.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface StateChangeListener extends ChangeListener {
-
- /**
- * This method gets called when a model has changed in some general fashion.
- *
- * @param event A StateChangeEvent describing the event source.
- */
- void stateChanged(StateChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeAdapter.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeAdapter.java
deleted file mode 100644
index 3b46202fd1..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeAdapter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-
-/**
- * Convenience implementation of TreeChangeListener.
- *
- * Provisional API: This class is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public class TreeChangeAdapter implements TreeChangeListener {
-
- /**
- * Default constructor.
- */
- public TreeChangeAdapter() {
- super();
- }
-
- public void nodeAdded(TreeChangeEvent event) {
- // do nothing
- }
-
- public void nodeRemoved(TreeChangeEvent event) {
- // do nothing
- }
-
- public void treeCleared(TreeChangeEvent event) {
- // do nothing
- }
-
- public void treeChanged(TreeChangeEvent event) {
- // do nothing
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeListener.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeListener.java
deleted file mode 100644
index 7591f9df78..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/listener/TreeChangeListener.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.listener;
-
-import org.eclipse.jpt.utility.model.event.TreeChangeEvent;
-
-/**
- * A "tree change" event gets fired whenever a model changes a "bound"
- * tree. You can register a TreeChangeListener with a source
- * model so as to be notified of any bound tree updates.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface TreeChangeListener extends ChangeListener {
-
- /**
- * This method gets called when a node is added to a bound tree.
- *
- * @param event A TreeChangeEvent describing the event source,
- * the tree that changed, and the path to the node that was added.
- */
- void nodeAdded(TreeChangeEvent event);
-
- /**
- * This method gets called when a node is removed from a bound tree.
- *
- * @param event A TreeChangeEvent describing the event source,
- * the tree that changed, and the path to the node that was removed.
- */
- void nodeRemoved(TreeChangeEvent event);
-
- /**
- * This method gets called when a bound tree is cleared.
- *
- * @param event A TreeChangeEvent describing the event source,
- * the tree that changed, and an empty path.
- */
- void treeCleared(TreeChangeEvent event);
-
- /**
- * This method gets called when a portion of a bound tree is changed in
- * a manner that is not easily characterized by the other methods in this
- * interface.
- *
- * @param event A TreeChangeEvent describing the event source,
- * the tree that changed, and the path to the branch of the
- * tree that changed.
- */
- void treeChanged(TreeChangeEvent event);
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/CollectionValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/CollectionValueModel.java
deleted file mode 100644
index ba25cf9262..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/CollectionValueModel.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * Interface used to abstract collection accessing and
- * change notification and make it more pluggable.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface CollectionValueModel<E>
- extends Model, Iterable<E>
-{
-
- /**
- * Return the collection's values.
- */
- Iterator<E> iterator();
- String VALUES = "values";
-
- /**
- * Return the size of the collection value.
- */
- int size();
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/ListValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/ListValueModel.java
deleted file mode 100644
index 65eaa7723b..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/ListValueModel.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.value;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * Interface used to abstract list accessing and
- * change notification and make it more pluggable.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface ListValueModel<E>
- extends Model, Iterable<E>
-{
- /**
- * Return the list's values.
- */
- Iterator<E> iterator();
- String LIST_VALUES = "list values";
-
- /**
- * Return the list's values.
- */
- ListIterator<E> listIterator();
-
- /**
- * Return the size of the list.
- */
- int size();
-
- /**
- * Return the item at the specified index of the list.
- */
- E get(int index);
-
- /**
- * Return the list's values.
- */
- Object[] toArray();
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/PropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/PropertyValueModel.java
deleted file mode 100644
index 82ee3c0096..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/PropertyValueModel.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.value;
-
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * Interface used to abstract property accessing and
- * change notification and make it more pluggable.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface PropertyValueModel<T>
- extends Model
-{
-
- /**
- * Return the property's value.
- */
- T getValue();
- String VALUE = "value";
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeNodeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeNodeValueModel.java
deleted file mode 100644
index a6bcea8cdf..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeNodeValueModel.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.value;
-
-/**
- * Extend WritablePropertyValueModel to better support TreeModelAdapter.
- *
- * Implementors of this interface should fire a "state change" event
- * whenever the node's internal state changes in a way that the
- * tree listeners should be notified.
- *
- * Implementors of this interface should also fire a "value property change"
- * event whenever the node's value changes. Typically, only nodes that
- * hold "primitive" data will fire this event.
- *
- * @see org.eclipse.jpt.utility.internal.model.value.AbstractTreeNodeValueModel
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface TreeNodeValueModel<T>
- extends WritablePropertyValueModel<T>
-{
-
- /**
- * Return the node's parent node; null if the node
- * is the root.
- */
- TreeNodeValueModel<T> parent();
-
- /**
- * Return the path to the node.
- */
- TreeNodeValueModel<T>[] path();
-
- /**
- * Return a list value model of the node's child nodes.
- */
- ListValueModel<TreeNodeValueModel<T>> childrenModel();
-
- /**
- * Return the node's child at the specified index.
- */
- TreeNodeValueModel<T> child(int index);
-
- /**
- * Return the size of the node's list of children.
- */
- int childrenSize();
-
- /**
- * Return the index in the node's list of children of the specified child.
- */
- int indexOfChild(TreeNodeValueModel<T> child);
-
- /**
- * Return whether the node is a leaf (i.e. it has no children)
- */
- boolean isLeaf();
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeValueModel.java
deleted file mode 100644
index ec87a2771a..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/TreeValueModel.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.value;
-
-import java.util.Iterator;
-import org.eclipse.jpt.utility.model.Model;
-
-/**
- * Interface used to abstract tree accessing and
- * change notification and make it more pluggable.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface TreeValueModel<E>
- extends Model
-{
- /**
- * Return the tree's nodes.
- */
- Iterator<E> nodes();
- String NODES = "nodes";
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/WritablePropertyValueModel.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/WritablePropertyValueModel.java
deleted file mode 100644
index c2ddacebe4..0000000000
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/model/value/WritablePropertyValueModel.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.utility.model.value;
-
-/**
- * Extend ValueModel to allow the setting of the property's value.
- *
- * Provisional API: This interface is part of an interim API that is still
- * under development and expected to change significantly before reaching
- * stability. It is available at this early stage to solicit feedback from
- * pioneering adopters on the understanding that any code that uses this API
- * will almost certainly be broken (repeatedly) as the API evolves.
- */
-public interface WritablePropertyValueModel<T>
- extends PropertyValueModel<T>
-{
-
- /**
- * Set the value and fire a property change notification.
- * @see PropertyValueModel#VALUE
- */
- void setValue(T value);
-
-}

Back to the top

اIMTb2 ~E=w6ݯW2 4Rtfk| @ÒM's6Vz&=60:ws_)*5uA1]nİ%nM'glguZtw>7e\?c" ^S9jNk7dĆuiXg-fu"bY?bZ)HPm~(~xuUq"W *9?GJb,*RD Kn#gV͇3IbLt_ 0FC:ܐ~6D}eiMP3Fx,X2-9Lx(4Pl,q&s:ZBfbgU+" =EQ7*]UzTxS 7X(y$2 l, I<Tg\3,vxSX[|lŽvzZ<"iI2V'a-ݞ|# ɾZA>Be2::6԰6&m*1sjoϮhw_݆~t#i9e3^ѭXOH@-tjY%o-Oj"/״Ě 6CGDeG(fJ(MDN!\Idh/#49c$GI~ae뉂9[f񗥃45Q(w wnpKJ%c҄#W<5"!rLvJf@5~)5 KYͱr:C;ܒ&Ttvp[{ã}}Wymɦ xVH=Elkύ(Űd.=ƨgX/d Y 2lQKo4ջdT-s ev|6U6/苡v(:)7}mQFI@\z%t[1'?؏@17(H-Pp1y_~XGˍn3ZQ4hkD*a"]>h2s`~#d%[,Qu)Y/w\0,8Y,tEHpP Svțυ;$d[H7U?5VrOnOjp;}LӅFL&ba$Sx=,M'1GќKS)HC7ܙhfLivH0ܬ @']&9N"}nu͍}6Dngo,vDry9rP, Ϗ2Ɏ:4T=vEJ#!FқH1V D'z]݈SB45AEShݔ#O1f?n4AٓٛOb?G\1\>A^>WBe~ut9O)Su+m༠<麌fx%nӥ%3Őva.:!v&#jm?!f&XNobf"<r%iC^BO"?5Zhas #ZXc_shraւ6RV|Jhmy]UHp?;71g='B5P&0?v= I/G^BgL֥T}xapTZZ'2Rʘ,VW8w+멿 0M)/N!( hRPxKn4!*w_ٸAV΀z57"]R 4 aﶰfedcE#yEfUx`*=\)Gg爫<5էk TU!ok02ݜ{'#.); sWzɜsn/Irk}b@de" D)c\$BvYtU5ƪ0iz^)ea8mSn*e@c}UMOz=t\}ಫf;K̀uMf6<[I[WB`g=Z,\IJOM*&gDWr=`6ҳ_Z7^M7?ip&nٵFF"]c1|Lb0W$|MaG?šGXs#C>&!Z?Q0tϴpUSDeڒU j8 ?Q^ DaGp;1`BʣHY'cUqVIF:0 ͪDY'ŁXr6Ri('ZۥeĀ1EO+*E!墾*w=41*$uA 0x) OND9RozWAR{#7EÝ-&/ N5eҼ{ a+t H?gf#F6nZ#XE觝Y";,ŶDtk|u\%fpg8ZRSz ' 8ᙍ:Q&B%gn P2j_{řpZt>v[+gұ+k>Du 2DУNŒs$ ˶DsܑϠ݅,yؕCUשQ6_:$+MgHpv=344#I 4/X(VؒZ{?EN2KU2[6[kP{B ғ֫?&04HUѵfpcb+_Ib/ 3*/npxj nZmqDn/"wy Me\ xRsd+rkb;M`8^n.Y&v9 z91=**f.XPqcq%ETQИ#6A/Ηr]lkNjvpf~́67W xmݡ|+4,Ç= p N`3y̕L ORܳ : <#El3-hױz;۰odA+D?R4tz(|, QOd2MqRf"!8c[uAMgN^ⲳ #~ f苔 MFe[Fq8()A%H0na;Νtl3RR:_`A5lu(ڗ381muAyg-& ̥0]V.y$Sw`5qW:jϫhg^+ aԵA֙Sj;pN'G"C5X)1Fph`J~7,jtk=1/ 2h( )9(0y/$S'Yr5 bje-,AO.TQj w4Vo5 e'݈1 ݞշD>:~d'QW<$mE R %Ds&iY CIԴ\} Ў؞uCBuC ̄Waxo. jC=PwD%0Y?gK>.9פzf9hi t\1hը窶DŽ,%HRx~Y [XQeyx FCi8]AY4ό)e?f?MLχi0ruUE'G1oyZI5D?m펹MlVǢ+4ųaH+3x@$^ DBE`-TN.ǁHԦR@] dg1_b)k[C>R˨U*y7پIcL"9ckfoXD0aV0:,'uO]Zgй6O\rG}R,BwUSC?PAӵ1NƝW]ƥ ,!lƨ?[M7Dbu=]bi3Ԏ_|~-dCynRYd>졔%W2Y'pv0ݦ-kؽU{,eA,=N{Lp2Qq-e.Y@s7,D iSW#ѫF$=nĮu1 {)l (#:HJMH" z35*b!VLRN @xU < c$~,]UeX!"rTm0|ҙ"#77BV^g~m1<fRW3?@\fuŰuWFAefCpCgc#ixc:Ru3DZ*kc~ovs0cvTDS{@s Je$3 Kݜ#7qpm88#_b#Š6Ԉ׊-1WJ_Z" {9j?>1iM37F ' n4r6ˏqx-KjS<0'moHOvۑ("ϬV1D8RQX-s6!2Xdz KlC"&*fDFbwgI nS Ps-;E8Q1xpG"p GqM5;.^eW.oڄ|?=(&#&:")qVOZFYf SPaĊl8L?&Xp]xl۽uw>jp%E5_1?jG &qD?.Ǵ4ZI,&XUe 1_2dÂxO B5 &܋,4s+GSKaJÝ8(n 6"D)tD6i[hRjaI7Y{ mrvo0}ndW\)nn|sL7eBewǕ`2G'<3"\kOү;vNɫ}'۫H=dF{l>/ @ߞJPZM%9vyzvPdrC"Y~F;Gd!dC9{r2d6gsb J56s7},X/l/>jl}Cjro97R;EbBLO&XͰ,1r沲dט.VvDRjSSU'1 {AѿKn}fR0&`O(q?6ǃDcgWƚBoo-{fͻ︷t0>$:E:{oъASĴ+^`m7FbJa5kP c2hd8UqaVR 1o0l ).å>B?yEylqˍ *,ɩz;Z{mpnM1)$o%d=f> $rQ¶\70E: ]9eq2 v9V4Җ6|?n\;pP+| 5Xpb_NN@|76?jS;Mt4J9swb>c])iJĘ+P \h-{?EhR( g'2@廡co[J`$iz2{w{0Z?*9C& فu9'(?1loJч{ɹwt6~G`Wֽ L~ܚɜ߁{sD-Mj~D?ś?󕌘 jY`Hc! ~gVp U:;DH'quj3/̻/]CU`%u-*b)3B5Yyԅp_<ءܞM=C> >,d'#G(ɞ>7T( ehNՏ/TEGme_DQ"vO1ޚ fXfLMv?B8x^ pj 3I3sSr0UCYhu;14GN%jw˯Z&ܿe-- 9kgNQ5< |@jgU\Bd?^P{Ptg, >uKʂ; Úr YIJ5ϙZ(q-ӖmjxŔٻߦH1Xm(KyR jj&i_qWNOp& h|8CNr&p֙H3g3L׉,RDdIe6'V^}v!%ߤ9n]_.(bQ R0Iu?C!d}쇉ȥ@e:%<Oh8?G[ *`U{tpQq,' 4EjaJ5)7[8z&:LsM͙ƩI#3L`u䅗 c:L.WƕJW՛a@2IRx#=@{{!݉46 nf?%uuҹW9)~[:jL oHlD.1J$ _G$A"NV>?P타p2d02oW^G2xo\&ՆoLX6٪%$h`k`2["˱%؊.*6aZX!E/ne2QQwz=6LYqveWqNTᾑ gkxρhCp^+zB:Ujۀ-.TyLBC8s݃ZėE%Dx?vu *v"u)4D% i8 ;Li~QD׼BazNpwPlצ:ȟ,J*$>|8ř&Wr?J$āW? tF5[2cBrku>~s*YXQaXG |Q"D-{EX"Td(%k"8,@~z R} 4kw|5[*g}G ,0[8IZ*Zu&^~uWHJX:5V{|*EՀKǎcI1'zl0\>4uuP0G{uL/ȫLTD-Ý會'ĥ.Q ܟ olǎk473EOpV2y]ƞQL8zη3m]Eܱ8ow\Â%EzMy+/ؼJZN?mS{fn<<: E"}V;sJ27!>&sư{y;66}AHmO3"SN]W.M]3[2!peh8a{c4uj8Gn$عQPہNM3tQ6yu8i..oA̪1ӂ=OFV),&ZYM<)} !L#ft^C}3+0?2ZJyt%7=JEcbzC/!G2NwwB+2TuaID}C&ja qv{{Ǘf;̴2.v\cѰ<֎1neo9 UA4@dr:f 䮹mC7"Ek[PX)3as3 $#ɶV1IfJ_PwׯDž^L%[j論ozaNr@ HR} _k.3ت._z*=T>(0N/c- ^NҵzX W.e${cvJ_T9uU)p/shχ]͆Ov%y4{4}^L<2nuEp & 58j pAf<]/ f3RrSahNEO_a#Dx20xG K;pP{\JC~f%7yjM~en<*S~):}y* Yh G:Xi8U٭%C=U1jpYXz#ngcxFD fLe`p?3E+i. ڌؗ}gZH 6nk63@[1 usԮ_Ћ /,adeFJ ^IIU,NԬk`4wd8 &`HZM4OLDt$t.c_vyM1^Mj8ؘޚF)h_'~:g:ՌЙJa~,3sJ{ʄ <^YP䘪S{w|;5(V}^ P7Սۭf EҹnN}%p;YU:Ng3 k M M oeۧ!$#H@[lHp?YccV?g"淜r.C2,!ë>%'{%MN!p1X;R5jL,-jBr5ļ!oY  r˕#B_gomWI(R[!.|]e) iBHȂ`c; ^xJIX".σ2HZ#96GA"/})Y3N. oUm~6k3n'(|%*U/6{aX@g/82Z%Z,]Ҭiu zW-/ e'f]@O56νwo;PYMOE":#i'O8kÏh!pUpx*TVVY ^c_)*IDb 8Jrh?yyq $2*u,c:%DZ<%.U}^Rpp"2>,$ +k^$c <h(B@C+]!q@TG󴗬e0$K?"i{мfw?TT@FVDImĭ; o@-ԧJ 1ZDNϪE%[kf64 &(hS7o^:\HMњI5)̀۷WIXecvKdb,럴*`<ⵣ^$.3' م/ #oDA= (/R ynwzwbA #(˔+K$ j凫e4Qvx}{tGUٺ P~fSz'arLFʃ{ w /x'EE9 zEL(LxPwtݪ KКI~E/߇*yqL!5g O^ʼn  r((ͺ}eK4pYHSX<lѸlD}XQxE$71yDZx* "Sˋ>V&[2q.?P)B$ 1kBi`bTXc>^BogcFdCKHݻ9R3e]WS#0˨͜ ՜,ŧ$idrld kM u>pX6=`gH@0 ){q~j{9Fߡ/d=@d34!|B$fmh&=M>]5O=OF y֗$"(hA  xLq0~+,?m@YT! J9sޅNT㩜gE':*(4*vD w̱d\ Lȕ]p+Y8#~xRǪ3ݕO Lc\0sNbYc{Xkooy)q-hWjwB=o[$\09׿ "³D•j=ZS0ǘ>c>%0[s.&ؑ*SrKRjUr,˿‘O[2X9 @7[;807TO+R%A}%e]jĜ  ~ޖBNq94w|~~,T0K[BP'zaJܨ7oѺ x8e12lϾ8%(׬ǍS`(=HH N1H܃=r.~ e f\,k9p,UZ}s޼;E9'>CcÞk+?_S\G<$d8Lݽ6RCbK`##O>gࣽ6hO 26X |= Yl;:0ߚ nN{"Ȗ֘Gc^Sz[w}2LZ;cH@֊Ák!kb1U@P~ Q0\е>I>ap\֞)N? S9 {їj4j1,ė;Ϝ4>,u9cw~N]j"A!qzvSKR* p,jZM~ k8wjHg[A`-R"8ёІ_$ F.:f\."4  ׬NN7#JWy|WJJs[Ú-> lxY7%Kbfxk}|dQ&{1 WbwP5A XW3+$RCPѦR.%:;_*+'Õ@GZT6L OB2'ӹ;jkX1*\j)hLw vAE/jQ^ #66K<#ZS$O}<d߳9UF~? O:g^5aGgVXa0J^AR_j!{ OF"-Nx*bM6"UL KDC2EL=a~X8 ՄxZYK i)/ѡyVA|Xe`,E=}(Ȳ]Ew@0q[qHg5{^6=ٞ]>|P0aH(;=}KO 1aqV(-͒*}P&¢[ltr;ժLmv9d~0|3F~A'-"#O TzG֒ok`ע,]Cjmmx Wvk2 NK@zэCR{pRHF &_ i=TC `ah\h}kxbR9Y‡w3!_S;QE4xMA9tBгY1a{{pş=fIT EFӛcgu}bz:qS&KsUYטLv<2amik{Uퟋ8 ƹ_vF@qwӭNIǦ)a$ݫAeO a Vlnw,dhXRWfZqGkpS1fa@WRrQZ SbI2bpS dޑ>J1&Xt6A-,O$p(WAY!4[ly0XfeP<->.V h:h '6@j>+3^B ]+~rp-5nHFylp쟗L ?+@:nдUssqkΖlI& `dui:Z-iY>{x$|8گLOٲg;dG*IN./牳)c =`/KR6U'TSbt\ZwDaa[ 䎚2RP /d\15jlpeb1 a׏I #Շ_幕!J?u(<282=$J;IQc"{x1vg_ȬkՓB2F!~<|>%g$#qZSbx[6KA i-1bA߉Qtf>C+I#sRwo_tmۗc.j:샍}]i\^Fwx_:OԖ }eҺm81XM?s QH~AO)c.E[XKCD@% H%{Ӯ=2-I"|p\9n=hoVL{'aC"K5'~"wRDoO. WV4Y.?`uڒ9 yؘMjc鬙cHj LMl2ke@@Fڿ^}OCi[p~R6UT:ry(]]v}V*M*L} ZÛQ3OޟFK90ve^"Zx }xdBNCߵB[$k:B"Œ&]OzyT# {0@:SaV#o`Vӟ*@Au .P5A:譵QitVņ|j&UfUie,8;YPJz~ZTh?Pz;=mf (BcNY!jT# U{zUW79*B1ꨶpY;xD99p?+A'Ȯ,K!P=9 T2 !oˤZEa04gUi:!"WSGei<7$2U=ڂ`-U۶Lv!K`Jǘ}(؟#!Gs OKG? Jw C=O^[' h`}5,$P~I]%(+h:X9膄s)M ';. QK#>pjqAZ貾3 G§2CǪ+,F"QF.d"N$ZEu7PU[@k(ыC ڤבe\#섶7u)Q崕Kfq_%b7L\B_:Ļx'[6#iZ(m虡|Q$;aΛPDQ+ Uz73CL,psY`'͉EN*Ĩ# 0<넲pXl ԪSJZSkj{XdzOBAVL)ΨX ;l[[.P7rJ10!;9xgc0+^,"|xU7" ȩ+&E Nx yuy}G { ƣtP} .W@4]zItnbV>Q5j JIlߏQ_lt%[| 2f|`_6_I$'BX}9"I5a +_Ӥ '{!~fD4KB1]Ą6ļ8a$xX]鎎5(g.Z%MaMlL^g]9{RhoWdk&OwvE6n!0=|ݖueBA$"gdU(!n~ֆW a".NNjX{Jjts ('}}C5kdDp N3,I#T=\dEcUv^ju-htu@>uû{ 2ؾ_Tj{ :?荋a!,~"Cv-w6x>DX^6w9lT#^9⼆yim`9[ 4bq=m;C]TOHxy4a{"P|GȂœ˲.JX.2ǻA@[ub(dho]6_}yrOq/`uW'zxzuQPAٔi_YF?xm]1KܮՀr^^aFHq[ϰ4D4|Xh&r/eՋY SGXJjٮ0HRHh\o8F_e1 .ⷰ^IxUꍉma65n;6]"RMH횆Fp˵-<dE|d}Xib{keMt)ƪ1FLA+eeO 6u[I$A+?hȒsR uqS?V\x'="#Qd zb>aUl;ؾ]sq_:Q{ksADl`^a0 _dZ`c|sO`x+xNbFYt6LFO qm{.=u ?&-8LҪ+ip^ yV)u$"%mB7RXLkHؓl;/~9?`Yķ-EOWasjߗ-w|ېdF Q[2ښsFj0OJ8tq~W*3hZri1xbCI Xm_CL ?(6A?:9Qt5= N'%H}v{(OP]W\xͺM״1Mo\+t)ݥ'j>(paߢ>z{ߣHݱqP#S_~z[DIŚh39`݋hZ\خ |7=6OYǑb`dgf@;K}50'oQImx"%9Y;פ%?DT20|PuwyFQ2rj؞OQ]2Z@XN|ȼc vQI`TtcߑIN571w =Gp(ێ"+Bt:{ejJn>|5n΄`Bkit BqH$Kdf:bHזL)!vmTszÛ > i#$7Θ& xNL%]SzVLx\> kePoТ`=0ZZ^PmD{O[‹ñ~g zE}Ke:5\,>m<[Z}Y_|R3'I~U'g]Yq\P:RYZbD3Q,u[(Ѽ}aWDzzL[g\dL58c Z)YOg!̑niz-p OͬNM~R˺Bw]He2Fo_8V~dW Z|H+Br>)7Fl1aHOH^ 'wƢ$ eYfnj㓵ѧ!W~ T̀PM0Uo5NLf3IpQAmsI |A*4|`|ܲ!өx6gS2U㛣n348VI(}89s\biNĢU DGd҂禼 'mCHPlj V9;肻"~T]? lYts;}Xf]Saq|KTSHIOF+~ef#5J cŽ ?ݻTT%'̆t4&9#p)iNDJ*5לH>sX`gL$Yd3n:V@ᆜڥkk,ɷ]I$RJ2Z0*g06#SɤJ5 OOH .p'U% /;5&} Pnڨ0`#-\/r,pA4=jgg'zǕptdy0bKi MBSs(`l44;dNRTF36ZBz78E/2DK0W@ߵF+ώCtuQjEVPu? 8 0qʕt܂xA%*mpNJT#U=pN\u5`3e-[R1WdN6dL]oqW$;$~Jdk+E!vd *Y>g/hyٛ?4FCWOrtwG3Q,kr{L ̹/| 7M$]PT@ݜVӌC*E بl}^͖vM/c2Ӛ6;J%fnȉRMKMۘԋ6F8AJQ,<19C4װO;S3ټ5mѣ{ ]癊uN QZX–9t\ 6f+'kwvɷd>R:}^t`l DF6~l\8Q/wL(!CboüCLճJl͝A!z@ |^4#_cM@/!=`8/+j=OQkH=κű#?ڡ\DС/y7 1i:Irbn<Çg. ez>g] RGˀnȔi2D,oQ=s=h2p?+E9v&_)X,-y+lUR~O!~E&>pHKJ]FL5G4 0vr[1 #7Jع6 LF, qϊԍoS&>v0Z\D8'.q."&R#5z}y(BPfcħ̕.V`%3+)h =/p*Q1|܏hD4RqIfgЏJɾ{0WG U ~Tu9]"77 .YLŜW=Cx:nxjOlo(І4nV'=FoƐ,4O+^J8 ٝX_K,+޹#6w+BIXḽO. Dgt`U+.*KSFd.A'\RDʼn"F='J9p'qfHb 47KL:b[>Y37^xl0{ ;F!u $:E)Nt&u0426LS1𹉢rz)+ \rx ۅ2J AEwtbX%>#t588 #sszU?e(cdh4z\tc)w E)nIˏ5=9t36C@˷#@Zsl`^iz[NNNd"*X،ĵwcdҊtS~nxS\<4IFzlH[Z|N[FcUtj_`ŷ(l)Az <ùIщb">Fۭ=M5kBiZ0LHmB7:*h[8>^q'!j}@!Z(s V"p2ks*NjV7 B@_ls"BN1  oq Tb9]-s<~)1tB8Emv 4M*$`+%C,  w2"ax rS41=mX'(׀3˹}~O+1j> S4Wj.=Xo6Օqa?(:Ώce?@4tli1_{U1H]”}&$jgE5Xv 18ǖ=e7ߤ bO[tQ L;| fZjz8pPbabPKр9.hc uj^gGvx<0L}D,b\] Au[LՊTг,W Cj Xvøt7=y_!2Q#M0[ q̬^/yBe]2Ԭ#8VhiQǁJ7-͓- A1,7 7>Ghzn=*ʽ6SYڡLm *a`wݷ^}N/r#t$ `'ZBS]cEZS1VhrrqT!VX7Fp鸯XB~b̾hJ\@ - t!ZkWK=?\Un1~ XԌb_A,9NCdR}'?ύ>;+SW6X2x‰U>+_Q/QuxL]]WhnʕWT! Z/[*+ E-F3om!_13+Jڠe b3I{sk: u#'۩& Pzѥ8Ti((wVR'mt"DR&oP74M"w[*Qj+IMPePʟy8Gʀdf@ZF8ۃK?{V[ǰOB0ʈ7 c19g5w5jV?LI # 4=8Q$.9i"&Yv]acQ~N?Q=`ߨݲDPX~.W lHVisg1T`~F Fǭ7,.+!̞.G ʋ0q7yP GMlp˓>af8Z$~u& m %9Dv yCa* Z/"6.P~Dd hdhr#TVz![Lf$[1ǵXsv15#Unc. b\@|aK=uR}TZPKt3.h-0ʥXab[RUmʧpdUR ᄱ) .3y]}NXmUc‘47v+'ij)7Js۳lg;sc`uJQעy)h(,=ؐ5(WV?mZhΛig31j 쬄'օz_IK0txeBjͤ qE71Bd;?u6avNA?2R(S SE{!Z5xPR#3֐de% {+>pnZeISEAF;Pmo6"3On7]ih= Z"Z.)9 &Q)"˔a43M"FL¤3v2lu޽Xy\jJghή sWKIJYdb`AyME3jג8u#vY_q00b=}6,;0Je?&vpknET5V'џ;ZZXTEB4}٨C^uG3~aQ@pb%p<Ni&Mm𜲸礅!ӥR_Mv[IMO^܊HW_@Ew13Ùgo@fc6^DZ$WB~ Zw;S4709 фH/(LkT΢"*L*ۙk)S-u,Ψ)W2JK 0SeC{Vx@3]3dlА(F't!aDd*-e ĉ%Q oTPz_̆7yzόOzBr^@Ѐ,+vfcUpx+<~D(p_p#FLy[9#By`U;ۼ] vU caz#6m>왨Q'Yr3^`, $cҒ[tiëMA4޳p/g6"-l͍:'1+9]zIh #ZMNo!YKəA *rZtHGl $BM6eJ͒QEt%oo@-= ς>qi^()JROYS&? eyAᦃ[,Z30?-Bf7gU؋@P3Q틡#dsSpO|r^E-\A90-REke]?2 BNb<.*b";8xֹdt>q1F i C=n~{߉"S͙U -/DB@nEt7ege>J;3eNBG*n|qL5,=B7ڤIkׁ?T&y{L^3^CiiHBX>mmT CA`I+ O-&0۠y{g8292 Ֆ!F5U,ׂ|` PL=] CB6!dn:[.ס/'u!3\CþD)b;C7ll) Z g7uvu9P`\}&SPweR ]%4,5I?64I3q/"~2w>*~%I*}&&tZ@,ҜՅ_`"+m΅R ]RPf٠ݽAc۳! ?6(}3qd+uvq6A^ H CUi[лi-6u }T<A[\Kr^.r `qH4N5 a_tAU99) 5 mηD~d\KU Q ʤޞvH dkb{b!5g+/"BC)3b;Azw-w3TFC$W&4gmↇ64w]'"N+ )T22{υV@L]rFZp49HZ: d^N~`ps&RŊ\t $[j1qP+.?;)K(墾 k-H5,FKmzZ3vqH;WBC: _|l%:tF sg$%UPwg>OK|Xs Wx够)*Hi;U>U4 xitLs-`# PwW|Zay|J{𛋉3䙻6\YQc$Sa\?7X {H[j=4n7?C8kR{At;0sm|Bi*h\:j 4#bxO̳ `K9?Ur+GU  ~%AgZNKxl;Oe CB]BDrqr{x*ca@B2*g,a,]6ԫz]s<+)x{`3aWu >[GkOQlC5dIzStkh A\զ2-$T`Bۿ$ Vg{1h^=܊LxcH9D~#94GF*%/y4CW|"HrƉa{fG{HK+ZuIIԟD3qu]rH Qk#og\+Hr-p8c(Kޕػ̮Hu. S{6J9r-#<*Mmzaq q5?fgg*:y  ff"<ԺVf &Q/D/S1I]WK7@&e;Ndq_i&TJ }F1STսe}ߩ^saڶn߶Nǰ7LG7؟ ėbG9C<5nP* MCW^?6@sVRIڃ"܁fbbNz,D`<9JolὝozެ{ܽ6(D /v#vܖlFۀ%p],eE:{Ϊ^B v A4тԐ4NH?,FnP`Tfi`ZĬ %_4_&$h':"< 8AfpS GK`ld_)t\ǰ1.ta:<.M4R)C2{OPQ}'^C0bIc~/s o|8 Bn@P)$Ap,"ӃLN*@3kZ! zL,+onNMLƏ5&fRq"d>^࠳cUJ=a]'g,;,C ?dOLI;GxlE[T%b+G:x<+eo?2*̣}ȕLZ5C8<} Y:SҢrOY$y ^v_dOQPc䭦iSwqe6@+'o)…LÖ#sBg(JBW ^c&w_~gP"F⦉XS;hF>/!B>Ʀc,&d>vMHqx¹B\w[Π.A-] H:v*]ʯxYvZx{NM,x" N >Ժ3oB`]Z-V| a^>姷}S ©?o̹^qx )ܭz\[$@ r.zMP"g괵'h:S;H\wlC ֡9G86kA MgKO]fjE7ͷsG 5D AK[4V_ ;(-&f?Uza0(&ٰܽaSlmM=`mI$va kk럷pIM F45=BŽbYñ}-{dJ2'-t8ZN*)4ޑkE˒o] ]M(*2JK&ucnM&#4up%KppP¨ ge<^ߐMO K ~gYO*E"B(`&.-3%sd7lqiuKP wp@“EW%c I XZz.L5ޥ]yM!8>?5uOۺpEy;ڠva˫ dO-U&HsK."oO|p(}82g:5d ^A'&;š\IE.[BXog%Rф8<­Zy7dDQ(I0œN[g2OD'f#gµ2^{s>2 XC/X$Q+䐋EǭvDQӥp'zaWBf:JaJir ggɻqI* YF^wa'Z&*q \p+U$<3Fj6@>|4?l D; N#4s1'ѝ ̵aGfξj=GtCe^5N XDsi}49jÀF@3h'[`jg( Zʁ;L(i}kn32B<8~뀳&llb>R'sz-&u8x6 l(j9|yd%+p"ܮ k 0hĔTvӓo!j؉8݄sDXϬ*I%S?bo*f&轳tC'c^λAzir3RjiR'Io}fHP9N{fC*ԡ}$ci. ÌAߚg?y:\1__yk&ewl% .CybY0`/ RwSL emn%Y00 G,|Ud8WeMjZٌY2_/t6?Jj,t7Ĕ^!<Љm#Kj4o ~S43ꂟ~a}+2A5X|$ rg2"%VG[,=m~BL%Z0a=^Qؔ'j0 I$$>GY-)E]gV#u4zP6ĕ)wd:ejt,y@P(&w8$sG AeOg zmk"%;tUqwM u{}cO!ޚ?[õ)dZY /~dK:q޳!) 91#'ΕL\ x#"op+#~s8Oƀ#-Nn.A #nZ썠tes;4ő(On7][8&O ÛSJ7u9/RSD6́>MhLW</,Nq"'rNVa[8str efBq$hRIyetVuKz9FZT,~1hVH?b$(>bWr[뾆,j/UX; *yjRr&`WksՇITf@6 4GZ5υ7(r*d?o\Ft װͨTOQ;zȠDZmrC*>"g 4B;\Op³9uvu^̀go5v/t/E4H2ILq1)R|٩y{i|}K΁cPr~+GxԵ~MC:!nY^IIvk:| /5 e U]IUX!(;RIVvT7b,*c#mQθo] 32R_Q%sKp*$q8I GL*m*DЂ#>s i(((E>R^S;^na* zx 7gi}J=2.f'3ɤJ&5nj tb+뻧p |mU"tX@5&@ɳcZt7ϩ}ދiU@v2xYH#Z\*Wo(8 'w돒>@;pWmRŸEJ7bYPpϞC$9ݿM}5#NX y~-@7oO*4c"pt62dibp;`D)bfD{RA31=JpT ˉxap"Sk?Xa"BMnA.k<`@q r ?c(qԬK "Hj]MJ^7 ZX:*m8^*zy6/eW*dej`;Nk}G 601KP8Pf'1{}̵U@^o9 F(V !PQnKO Қ6]_l)U8v 5^3ې6V) o%t NR}ٖ:uRVݯlh~{gKMZQ4θ iZXW !/dQ Rr9Y! C&׎W"{:ejIמer;FF}MG6RA [F\ G/]M(gncLIYݬtcn[YUU3M'k_A!(_CU &ͳ\z=pmY(m ,4 8]w|D9}niw{'=" rybw,'(mf}?'A_y`Z##C~ Tܯ H$D"*253 N,Hs {))X%B]uy:o{Ց(uTbKWr$rצcew^:isGj)A}8&pz6r~}>xMh(ȉ X_8(9JI{z}Nb *?haT cI !ڋ遆+IkãEW \K29Þ],}`vBfR,?'6rs|tR[痹a}hh Ô3L'0ź\ D5jbҷʡ½u4f +A_o;fSq2o{si݂b؟5,+|˾w1m1b^{ ķ#FD|[2z7I@BUKxh%U)I6ZYn֩ I OI+HTC6GVx-6KpJ՘Sxxm;3/ҪNhř%T qNPͿMޝ@ةh|f+`]% մqo /״'`H~R /-k nbe Vc-ݾ4%Kp64Ȏb( LeR)w|xԙ9%,@] lTP;W髭ӭ4QJ7~p.$,^Aa'Pv<J?ĥ C:>߯>L8p]nKz*#8b%61i3=0* Sv}^θi#Zg{6.a@7+KW ~e?`Rǒ1#Ħo  - :Gi8ɭo 6& =$PjOaSB!YlSC+L^c"M \C0=~2ʗBZԷTC%$f9IQq0g>qh:ܮg"k> # )}@iw?c$lo_Tɂ]UAe9Ļ=B(`KO5b{%Pa]-/UuE |J;N[~xI~ =|L%9r]];H\P1 q16x/^ӳR%xAP/9ەl<w'g=0 ѵnԱI-N&c@SՓ1';:9kܑ+ɗ[^6oYpTRTw妦0lT]mYЌmm 2 $HNaщ+}.3˸)wPpKRwUסt/VI0~cIuR=hc4.~<۩#ӷ=hmLvxi~BH7j;5&99ciss<WZZr%^u%.F0믢zW[CϪݑj йJ4fY" hDf,1BQgzJx"~SB>vZtVt,k-W#X*/k"4\}dq2iݰ}Ţ75{pe͎PGՅ6coe&717bGaZˢ32:^v[mݹЀ*E=6$>f|L8kPc]M\")TݛItJ}ē3W*j50(t`_+?|#ܔLYMC,]bڡ'BTWbujlfqT=iXDQ}pTXjt_UP!E`=;mqqHC~rRV0NbؚDӼ:KK|S~ [|@ges`YV1{z˅f!g.8Fr~;^rׯ NsЅp6x DQIVX(b|}*(ע:X}AL-N%u* RDxGB7ep|F6\^wW3ۦːj*ST{~egSPCauҕ~'ؚ,ԆH J-JZ?⅙c/d X`gWI!Y7s43zX~W jBoABo֙q jm ?471C?& ?s>d1֞Vv$O}K%; x"H !MNʄc)ʱ 2c\HF[)I {@,1r:S\7u&%cVVCm/i]x(Lhz$s=;;GbuÚG6YbO'xSٴiͨвǚ(=0(LIK4< 5ynDMx{f35NkpNcqfmE(,2.Y1~T4T>>D A! z8uJ~dh'@LH'Ppé\8hsEl_HYy(ȕΡ }xn:C@DT!|R5]Ϭ] G٩3Ll̡4f79 =躹ލ_eu Z-CX2GdU{&܆AJɵ~yDrfq() 9JU#OONlou\#O.{{.^Ap{ 6G[h>?1Un>Yq\B9,*j͸z?z gz78#X܃>U޴prb>ωW]`X'J>kH3;Vށ5mJ*s;jD"I5xβ0}{HYChJyN+ [Sk>8Upl42+P؃e5lXd;*QI/7- lߊJ2{L1I0#"JbZuYn;K&FqAt?/?fH,jV;fR~eR}][W@z< ywg;a=+usi[Id@ΣhY?͈RsaP2j HudI+*WÞLx5.>*}S}g|7q]Ø$U1m#A~hF!AߧCA5$% g/x'%[㐣:ٔ$*tcȊp Y+ &2v< V-ItP*S1x)n-<Ւ|QD6O(I?Mr,bILKܓc#)'UJ_|*~I P, .S,p'oejyguh WVެگo"8"9#&p]̇#rNPXAroe*([6Ah;)]*NQ@W Ǥrbh'y|wu0[M* rZnI>q/*<ׇ9 TS^ []>yr/; K3ϾV* %];X\E! -)Xw\ ųu U.GŘ- ݧ r0+*(ei$. 5im(Jjtm=3tAܣu!;7FsO68Gƽͅ2N[EaR^n: jB$za ]dIhB x!]hbWhW)9rESLov0 v f BD9nl#u`!4̪r1*(/o ?v XpeiGeǫ5Tǽ15wŌfJZu)Ks)K@8V@xb,#e}&pQAY+6Pq!2>H><}=]d .@7w>m`&&-:EVl;m,̷UkIگ/#KMJd y-| H% Yw܁a=)yzRF qx7tEc#Y0:,^9UWzf}vːLȭa0SPjW=R@#'Ux5.f0765CU9_ӡxKjp(J"jiCVp>LT9/fհzۗ;9/k( z!Ijh9A-!56NYÍYbcjf;kz{dx4<>GRP*H!b [qT4'f{³c fUĪl4z˴;\$gi y xN&hOM*%{OrCJ~j.6_.eXTUa' '1+[p%*U@:bٱ7 N?|8ZM2( 8HPg#od`27g7סxKe W2 EndI52bl."ue1}kO]Y-M%UkR!f6d|};W ".K(r.nNSCȩyPHSnQ.OىL;YWR0}X{$Ro/;cKkաi [MbD9j#).5ϛVYK\տh}( IX*߸8ʍtl O7,Vu ZµMldED,#}3(T/yud&ZdBn#k#:b X0MX?i^$DvBhbJ&Kc-D_{lڨ̡CS=&.} L>ӟf8G ?}钛+bg'+CbZ |d7c쒎byzU M<`ܖni(\V=*/>BE1E'SuU,l}#Τp)Șf2n> zK8fQS-ERfCy &II:!H=[<Ƿ8Yl?vtf$DÎ]6;-g0q L$,JzG%/.gyc=='^Ta,H?ഊJ­mX3 %s.o\kf:R윞;"WM d>k<W3ՃOS [,gy ėKܴȡxՀv~(NMk@ᲿTԿP-lQKq į}wSUM`K{& ePZԭ"UY*z~-hPfET2' S:Fgu5qyag  ެݤpc|?F#M(mlg{zCXa8"B aEL˜t0F` M8&%g d)3ءWz̫QQ-'ub?~Ѻ,󶩲ܭ4gT&ƕr-UU~(^챳:*w&~Z}ّW(mx`hXLẃ9\RZqBq tm~iC6#hx>]6O8(k$ᵡiX$@!:\(|[oxXnE3M>4ceER~Usҭ'o=`fM]:ѕWk| }UI'&a*?^ s M/Ÿu``hNDr ` b< <;6gf dߢ%/a8) DRh|?S:r`fl\:@î.Ö'^iRM3ְVu\MkB`JZrlKo">LIpTˋ]5kxK&;kghR")!?a't76N'Y},7)CGh%(vBc)UMڌraosz2Wu!C@%.uK0(nEHQ PJM֖XS)n&{!m O߉(&T%̅0/ JuST2@s]E;ߩs&dE{72 ߼*aNEv;̅Dtc2qf9( 'fKҠp!gq3>@1ږŖ`;-ՠ)̅_.h=m%#\zEH{%3n*îfķ cez{?+MD*bϒ)g܈ __f=^FFOp T7P~Z YkqXTr!! m@iB&gs.ԇ EMo . +md+V;*{κ9+_8E剉:t"q?66I;WJ>d2(aNDJu ˍ# u%2#&#DȪ[Y5|rj1>gAə&WbA㦗^BfSI'ADҙ05UJDu/OB0@\j e6pC I4PTGudŒic-ӵ̊`chVmÒP)rT*0^i8gNg;ҭ\U,AًH=Lfdxw`Y;zΜJ,ڗLY(5Qt\~BowG`x|rycܮ|ze`8)yO9I;||%:VdV^/U<&LN)۹Xi +;j(= *lHt>$i9KƵ'R;$Lw_e]_=ѺsȆI pa4$c^aGѠ0gsɛC)-LxB>GϋQ;IsY; }[F c٘RXF99y)s 0eAyqWe<%6K1Uȍ0R@Sfxʦ a>.[oJ\xh7A?0[a^ʣY0pmFG{"㲬_o,p)`<SLqaVb^c&b&VAnWhUyJ W9[G G>SyhJ4xwoyVIwPQ< ښfXD.j]A4IRfGAV ,xcqدZ\hQytWx\ZhN#Ff%hqC0zHm%z9e UpeFfw'|w:ka/~{Nt/Kov8Ҕ.չmzrmVBjOIznSRw(Ez͗Iv G)X<\?5=p0}Eg4r_.4_ /ҌC:h.N|z@ 9mw)ؕ8dL$v(`CP8SZw dgG5x^fy=>l\-{*}|S>ё'G,4> o)PAWk *UFlLx 49՝"y{[PW"roS- v5,|0Cd;-qZvqs 0v $KSeOZBc:W+Hݢ:NGY{ W,DO]İ?𡈁Ѱ!mDA:#ʘxXXLQ#ia?n9-okʪr4z`6#ZƱ^xyN idy˥cYf_xQ}Pуb2֢F 1°7*Tۧxm\=ĭW=$ lzC:ȕd!ߊg73Β\@=M&'+%0oJO| i77o(Tͼk<%? aJjl]<y^0g/Oɉ''tZUE*IPD5xL26hwA.b㖖;LCyC:7A"Aiw{cKIu%(^/U\1֨+zT-YZY\ 2s+(C3NlZg^җ>ɍ!"C -4qJfuY͘(Y-x{la' vR4?J{Rj ;Bbu›:`Ƌo-OE=l8~<'A "Nwetz)Ag쇊aC?pCaL.c0#!\X[j:M̀ i!r}>I^x,4wJY9&Q0U5X6W (d]GvvX/P:z5Jc:L)u2/ ! .p?y0X[JpC}\/M~*W XSY8f۠/pP|Ox2|) im![ZiX4Ϗ9g=ii~M4)fnPMd…2nr )X7mٗ4EGRoN۽eҪ"N`'<w2AmHkO^o6ɾJv00q}aa-F@Sv;~az{ݯpF%m`NeFj 9b M&*e,"c+n^ށ߳`Ylחِ\픀lJ@HZ[>hu:9ttbS) r<*B^?g bTJFTN2U\y VY9EAzߵDgJB[;XLzNk.ZQKRoY1A%ɳ{]9TɧV jU1Lu}OUB]!)>+4XDά&Ek{)$ ꑢ ߅ c#zڭ(g 8 sݠޠ.WvDB 5v,6o[L+nOOm䀺 #IvjȮFZ.nAVn\ljga*w]j{hb5%A)u={i1mls TΌkNtI\/r3N9bnVۘڐ(fU;b(WōpI ">mHc*{>G2 (˰b~PC(l|fTޔq<硾-J1V䣁I}";׸XZ|M2HTXI 0Xt[tK#ݔ9O08OX^W,aZ WE<lKGKbxK.(5'121گa%~mr& nQyJG~ ,*,a$ n@R&{čkﶠg&GFOƥ'{} C7EKh Z9|b1OEإV]WLTԅj_}b׋){+d{H]~gr:KCĿ34Q3n|z YQ0;f˧64veue]k\E4߫);LwOLb]ksJBZΆA,,.BUii~DepvXՉ,8 %FV\Cs0خc9ս C)љy.滮ӊ85U羈"v=q*9I#։/SnAE,N¬ki;uqÃWuS5Mrm6/ w*b Qx TYaqq꧎gm9 Ca [Qݑ@|cU ﲯy8}s 01^ ue1Ii[`^Gb.cB.JF~!:tO|pvW܅$%=l) j|y}:UB"(Ot ^S۔Vt[y7B+2P< )Ԁxwx{"[YԆkM^t1aY}Zީ{XR-MzK]a8㒬YB;bg[\۫{7xd4*J?VGROTj*UXڷ7Uk `$k},;eN-񩪚P.7RQ( CgPLAvbs P5ߝll4"IqD*J;?w-̪ku5= /4N ժ:!`Y&BgSry=$[ܜ!@Ö㠊#ɐŅA՘oSOwhiQϮD[İij":>/ӶUr<= FP \}“+NlM;\ztR&XR˰ M1Wub\Jkz^QԶ a{3´6|7t \uȖÕ{q%L'졝̇Y G6e\>d~빂س<{.H (2p\?Q 峜r pVUs-uAvބ-$GmÄ}YKp z!l_OFrp{RvMD"B 5N|>~kQ!I rB&4zܕv#aeZ <$7 "A0YzRDq/=mZfjoiSer { FYC?g6N XA/,gI%+19 ܱ +V7+Gu$o:j40^~j]-¾n2iZQ%a%DJpL}Bn]UKPN=c+<˯*S"ҟ@r+R \Fɥ+Ry6o`k_EVn/̡1)ULqfV[ӂ hHPEEkn [ZU?t}'vS]2fFI"=.('r k`D"T^X bz.<),=5wtO-@¯FТo0n2AQ׻I&`ȟcF+2+"hH5٬ėGN(&,ܻzn>bk6aˁ \Md 4`B/YW:sHOCݧ"*ih7N4T `K0rў"_M0++Dx9;3s|v8ӡWp/5"9<+Vd@e땤72!Ƨuk#|(FN<%:UGjz(? p]Zg6-_.ڐT֗80A:3eתԺqAԥCĮY1:[;Iu %d%GI2pn~a!mA'm|7zy:@~S46~euKCZ5\Xfj;n8v͖U%hҔSVDyޘV?ԗ-1aķSrL엡5kBRzn $1O6B\14Fg ݔiB_Pa!#0YVA1;LUC@]nK@j;*7w~ȼӼ`."mQ*Bd8 5I񸮪*/o6;gݥ9pM_Axfe,edtFկmx$)G'?2j$7q(aDTAn+!)&KXnh,#y뛏?s4tĝ`"0b0 b nXjm?n6TKQBzYd8yspaP04-lGc>nDX=\d8XxdP@gmOz0t~Z A=cJuWxcy-Kom2h81m?ʃOKF@i]rq\ ׻Rq.d:j;c^g_qG3p3d6giZMۜ؋ʼn KS`Zs7 7R}ax"ƶgJ:_dSGFl:+rEsn6_kq~uT-M9c2{wgg%_ ʜmE>=1/_!WɚTJ,!5ew4hbmh Irۿpԉ 9/L4qYrB0_m6ܬc<>{~o~ca$#9s;v[PleL:tm]SfRo?o݃+AKQՃ"e`}b}k}kFZ\zY`ʹneNtSAqp%Jj3zLŚ°+eL?n T~y6GK0,P>\ki$k2Ff^!Zױ#+T+(WR@eS4Qk)jspWQ3}DMR#zE8b>NP:siZ^,F'G~̴j2u6U2Hup]|P^$.ȲMF DЮ|Ј(k6|E;ywGW9cq_ǝ vP?.kO#jQJG"g_s7ḫ$: $`P>z+Ȇ{7v{޲BUNIJ1sj SX 0\l܍Wo烱=|BO%R>ZHCaXB(3y[U꫘X1\hJusf_DŐS/ 3lؓi1~A޵^[DyL _-aN ź2r2_',+"rBEe(ږ=uF&V}. eAj$1ZfAb XГhF;ZEs6Bt8 Hv3RthC ypP޺jO#-aB$Z$ڻ&~uΆo.s J+@zCdu뼯 ٜD2}-:Je-{2Ÿu 1c=^ڳ#cGYPN蕥WH^dmg T%cޘ^xGf(/'􆻘ka{IXns8og0m"|š;dk`_[5*S\sDŽ 6]+nkT ؀GS㎻Nw-Y2wxye"Qϑo~O[gN~8Ot,t:D%R McT2enS?g 6vW.L˵,+Kxc΅x&oH*GM>1 jv z p+剃ICwR,/فՌ;:X ^g$+u`(dw1$@} ?=*:~yֆ?SWaIINtp4*_H/B?IMNf9(n繵4ʞ0j m+9 Kr [b[QϔxYqb'/lgG$^u0Q)lj &hfױUB{C!AQ-ݻr/d*+To[,>4/40 1K<_&۸RXYQԆ;* *y)%}R(qЖYH6\c^=WũSskCĨc"<fv%V\'K}]E/L3Flb{}`hRn V m!W~VB 7 _Uȥ0=@A4ri;rc?h.wo򬚻 Ϟ9ir?=`>&'08ihO/[| }*PIz!߇SX/σH?gY qcȆPE$ NAn2Vzs,Lԡx/4d=,b G-I71ko@0ʸSzed3F9vPvz qIΕ{M3@_tVhqN^N-YcD w0+>ZlSMn!xkkwS&堌sIgZHeN(oŢϳR-WDݜd%]Ѕu]U桵8K~hCr`ɸ(T.Ȥd_&sGW 0&Ս^U%yjĮ뤤AǏN/O8Xq :^jS6xWe0i$v3)(")%!mnKj1^n cz5S xGwt?BO[~N/>bà5]޲P/ܒ0&$3Y/yJb bXPR.(P\<q:#;V"U/MAoX}}F V Oe7`Хc7aؼc?t$)GQ Zm5Q1<2kp;ָ }#:|V9QE e96,B~BfRvLlp6xZ9CpV\6 G+ ̇""GzKza~LU+GwZ? |*IQqm6wL`@AfBMZ} |K~br=NyPk(VyL._[Tı7Tz|:(elQ" e K ZLjΟrsCv^,'A%-0K3SLq3FwDE+^8+wg)BF[9D8=wÒ 2R|h<2ae]ȭy% cKD%ْ&)mo  N]F a\=l}' Ӗ+|wbL|u.Fޱ>t6Q1_p6:5SaFoϯڸR~ڗD0F?@]*/݃eh% MS@:`UIG`;˝L$ԎTE0f!ںy̴dUEtdA hoTe۾0n/Wb(ܩbCV~%7 vKݻS(K8S F4^ThAj+!,NcDUX2as@HɇRh=Uzس:enWB'6ETV|NHYlkҢ5-QRɽipcӰFl6VauMb{=l_~s;bĤTkPn Zi +2K4u1@dR/EXt>Q񫤐Aw\5>b:ɷ%z~ ELs'KH__!p8䪬M3lB4Pq9/L2gHÉ솵m9a)Z/[^]nmy]8drdLHw&I.`28?)Y$[aCbN5JYҸ{ 獲鎱K"Pq %VQ뻢ϨV6b^0c&gN,i?d:bWPgH$CNTj$s۷݅&#g2</$$/Dc-_6E$ri.-['a {b_ <[lx͘{LOa_HݖBM^0VQn Wƞ&MA edW[Us}fQ4bJkƫe),XvB-I;H?tI XN sHj/hUC>NC$6gxh#ۻˋx7qܳC(zÇbR$]w,?~!xE8kﷹ-f{3 튚P;GJ}ܞŸI%Fge#RS"  9@ăLtʛ;:/uҌ^c(tΒvqĚ/Bv[zN>c+ F!Fo@b 웎F)hîz2z*}?w 0I'f;؞Z;up`뤑`S \H ÆGs°,q3C^}_,jY6`JUܒ cg1po*BW/T3Qt\! <uSd]Eu`V/?Ol_7uK[lإHڌ~w{!)!CJ.J9׊1 RG RQbr[8܀Pp_27jmiɟ-?^[ٙn_ 266J=RUJeOID#1Xi4og]@X=(`Vt=)4rWm'e"w|oӏKm±+4rRbGcr ;~1/rS!YBLnu [pQVKF9~Yɪ^id3B|֋>pxA<ZX>d\VNCDݣl"?F/Y:)@aL |^ Cx1ZJ sx9\-1ۃ}wgGV.XH(WD\~G׷FN@Bg_ᬰ.ufmkQk? 4]?" /}%4mW1iʰB4f@m HͤxS6zO4NpІX%?/Cl`PDmĔS,OUKAVZ-$ꯜ~y@ K/s:dz 74S5?/r`d,|Vy-opZH>$ |$?W8~Stcb;Zֽ9fCriWdrR(0C>@9Tz\ ٟؔ5\_mrn_De r0me7/ +v>RSN0;t7CYSxq?(jg{3 0z99]۫z ]zY`<2{*ס-J#"Wqg<1Pg,pmC2jtlʱv Rw6+ɳ;|jd/ n8xb-@y:87I.F#DY+H"9-.& lmb:Vad/(1wNr8t4i Mx FW{pBtj $"NǮժ\[Y-J<\ bem0c@S/Hp$Q@oPD~:x4tW7 Azڂ+m@CJ AOjQMc<8Gvf3RZ4Xڌ+`4&Wbt-_QTC80ԍXlB HS[ń#MǙS%#|D3QInF4qcè|aaL+.]Q1= &$8r$ nJp^4RGۛGMcxw>?"y&2@XYF!beLGUq2RD" 4f=bkw[ *2 8byĽydβ)ڿ?VCWQGA`%+=΅H+uaF ~:cN:oS/E"3e6t^@cSF[/_}L"+رrPE wQ'fS)K0&HT^ټ3Ib4>K%@T鈏3cSU.6×0uMxZ8ǣp$?ȱQ uk:O<~ \u<p5m׀(#]U_яUo&]wM,:#)7J|&V݇䃬>vŝ[0/H$L}Ɖ8k737{֨VHISiJM-*E˒<#TKh#baҭyNT+SMB60 d *n Ķ<DXYnaߪ 4YCH-ZS(߲q|,Te$*KQ-=鴏#wI<a_-Y(,THn'&zH$]抸0p`$^z$( +NHD@:TX_#]Lu7BNHlsZ?_3( %EӺy^Ÿ̱qv75dW;ζaleVQiPL^yNm xTlsQ{A'7}!$*C6rY$rJwZe:UHOX RZ֩l,4i쑁-/')7罧1 +bE'hdoz ྻ7<$.V_գ`X ,-5r9 vƐSwv4Sq)?Wx#:f ׳N#yE8a,;ș>Vwd;{eo}~F՚VYlsP3XϹ暇Tox.O$ g sLU~():e<`H,=G?&tT8-f.'@\&{# +y}@~1DN*Av;Wz>kEo]QOyhܓZ5<ǫ|3+UPFQ%d\,ʉVMD|B(ՈkC?̵-&W.F5ܦ|>A?٩\wvԕ>tH7z^Ŷ.ϰ=bV\u 3|ɖ&HMN" jl5zE+<8Fu' ZҴ4l ӟyE?P01uԵ;`j` NZ2$7#=y`gH*7/[,\6 fы4A1QjH.BBޔtsWo3lېKҎ:F;Gq~(DBKͦ:6L;]5wV#8頕o_,. {ٻE}O R# _eťn[Zsa2 !JXNjKf<.y0&cUW E9#_-G`6J5o͋cSfxw'~ 1Т4m,ȴK$T ^7H"Q5JMBFVdw |IGa2B\O \*P*OÆkH?kp^g8ef֟߮J[:ٵǜlII-1P]ww!WG1,vqqթ0b }=9u_  ky F ?->T451 ,6aZx Ϊ̻e-t2/ ~|?$nGㅓ"l3z?LS$K /;\@"Ӏ)%7W;ɨC:#g7o]lzn<|{̭N#Zb(|&fЍvkp5|:8MVYz$3<.m|AY9(b'n~Z_Udo \1լ2'`=_hkRvgh3zn6 R gO}]Y>cTl X?b6+_`?.o2nD-c9|sD>Ix0~چR>?'cv~DlawSJh>TЮ`1r6Rj:V#iv`GD=r胏+n=Z){ΘN5@6RJ^RצB P~",vfo72%wWXW[):'. Ɲ~ϿK3oz$x Ry|(܁dN4LqN>nnX5 ,t~, @ߨ;@'K5! 2xAoWs\ZkHs*VX29[s`׈QnSӎg<&Z晨D5wGkמ*ӳgKM<]x`t &8*au@+Դݵ4/cY9cr Nņ%F+BA\Ķ9Xꋿt(= ]v o˼c4 cpCbfFT^;;LitlG"ψ}/+խ'חT`,QPO9 %$7aD<g%]7-)}A<q]&[vPEmqB.5>zۖwZޮ/ 9O옼 F?ÿ3)h9cP JEbzDa37 edKJiN~+n8]`=g,Ȅer9jJU(llĀFR3b2% WXveF˥BՉ\HQ㰷(O$sTGVT c$dkC 3;8ux}jɯTZ 0VUL?Q|=ioA)oFpa)Ƅ^ΤNIƎm'a/ׯ{B]z"1$G60é^Z ~ kk ;(/Mm`T,й7Qk GH$ 2Hw!꟯ dK?5Ov e4vn2dъ/a@k5bi$⾭OƲOӝ7vYPN+NBZvFn z48"e]{Fd1 vI%}abΥ¶Xͥ*7>rY><r-/5]ܺ+yPHp;s:NkFȕ|vGق 8; |Ң7~_Aѡ}oW|"xG9iW fvЗìPQO| MF提Zfۢ70u4;H%G.L?ЯWvtɁw=gѨM !|=^^\elɏzU2 gdrJatxAXo;BGde|m~^gN8Y. )A=M٘Ӭ-&ןr23p<99t9bYB=>/Zg6pb$BNtkvv-Ji7=:^ׄP`85(pg3v-0 dUg2*Doa:xwt-ҕ bq؇|ŦDx5ۡuan&Ua "Kh(boYކOa_OZ6φ j 7G{tTGc+g'ݑ5<舥!cA M1-61ծȔwxs%Q #:Kl\4"߷3Pç}Dm? S|ƂlM[(XWZJ=7*9?5AM $oaD,,7t= /bsKz5I5g;}26H?0T>?i>,Kgt~]oMț& "g..,HR&vjem(Ǣ?/&YMh7\Q,ފP ^rRx }UI"JL_x(nbsx $^95oW22&feIj}OHa6DOНVj [\)Rn FzڀyT&hF9`dTF]axИ*_yЖ,ng8A{V"#x׭mFit_&^]0vc.p,qGNg^Eyp\|;,UC#h>U) I w !-9WP*ta:gS%t{9f;nBcvǷ2L ](naZSVA=Q] %7<",qpi~P<'X.b5#n#Mr.u TGOL0 ö |D7,R|o EeVء%qb֧~|*d;\ZAJ{[Bij>xɪ &RG7ǡ$9+04w9,v_˱?ъDYAwv{M}<s-{̯9UmY R/&YAIiWUUG Gy-b#|:Å0=WCo$;2Ue"vt1'KeNYׅ´OlkE&t54"?qpn4Q11F>b&Gb'iF7Y}"tO2,[GD6N_jgJJm ۩p5uJHhYҶJL*C!1 &ȵkl,&'%PS '80{+6GH5$C݋(yXB޼~a@6Ȇ.OD/%t&<`7P:?؍s3L $1'H1 Ha:-#pg[fFK/weE. `-zJ e H$ E B~ɑZFxk̼)^JcN-!mmZ-=xܵ6-U.C pcTkiʦx5ӳm XS0wv+d걠VdLe=̩ԖA7g=g-;K  ɣh}mh\K%qϡꄹi 1]d B OҊb[;n@ OpڀK yi%#8`Or$&Y8mI'fIq`R8JZ*/+]<636e)Ό8WK`{i+ڒFFi7wfV)slxxmbqGA$`F+||ZH)VbcOSD ,-:E8zbZbX=@C49={fo{|kŃn8*(Z/´/#VMIߟunR^ <6zFM#%g v+gp6 ?Ln(óх'ViN]{eZU8N"o3g!Q]F:܍hX@XdK[ {3z xai4kVd GTQ!rK{D(3۪E]'_" ]={tiY:yRDDs2cyNī_MntQ>HHzx6v\e}% ':4K_4m(RpټWGm!#>UʁhC۩iL K"z5M'Pܙ')T`7@rWQ[Ôƫ>Q{v-- 8RZWEt骸S E eتW>yj&.̠΍8\ )TZU:J">Ym|Ɨ`>6MvhV:}d~FX/}!8-`Boi@A-J'bȈ|*hK 'b0T񶏿0&9ͧqJuvr4kc|R/3 ]\[?o)[to+,n"Q!;kE_=RBYHC=scusv࿃F.i{UXLl[ YS&! {/kȮ:V ڨ0X= ߝ_^ȥg3Bů;o]3yV"!j}L2AFAw%[B#Ys;HgJgeERz/bǁD;Ft*'n{HgUx!ݬĪJr3e;tQ;Y>seك(ͪˈ!H-+\Uz] `^1D-qMR0i]Ɣ0/eT|v Ɋ`A:ގk_9sp-"%]GF@-ro'nFSHV,AFB o!ٜT) 8V{EqśMͷBS<{g:a0e :9m Tk]-Z?'أtJ'poD-syጵXM_'7B0l`+=>8PRW{p'3=aΠ9o.A,w!V?ۖ#Od#\xt4&(R.ȝ(x& {j~eC:eK\p.Y̵dK?ir%G+ m%ktĚ5^?=][PSHGf7>Wu'u^ 5N@`- +psV3Bss*D Xz@}j?[U’Q9n=JVFm4;-i_;o^(*%:պ9kH%3 |\?i|wEs*^'(NWfI_QTqxyxmFI + ™L3 EYbgSqE>R*v, xD>5;+! a)Wu* *\̼ (&QJWhO`"X+6ؿapW r[W׊E}}܌,-WCr?bGm zb0ZFWLNؗK8QWf xv]tξ%ubHm|kv {Hhr 1I83˃>B{`79~I ^}~QO9Xg ῞,[EEs<"F:\+U$\2g?@ؕ(!x]VZؘx\]ξY5iq!Fy_$ezϑo}+'cP+4~srO\$t m W3cSI@M; LLu/wG{ ]+5H|Ain<+ B|È>EۊvSf*WHV4M=ٮ g|wA>JO_SC+W3#ݵRum jۜC-=nH9*p;O[D '7`XzAF0~I h~[@މXHyVuF[N+wyU{"uU@{ US83*{k ΄ cd gF[DOo+E靁i>UhneUWe eX5šdJ:5[{@^E2-+J3罖%OzRpBdλPt'ÿl!`uL?B[Y6ՇMZ K C bY 4lJT/bO L/(Ɲ-6E"G !F|*:Ik '.xcp^oq$CpX;rXQ>h(2{w;e 7 hz2aޑ?[#wGmp,߆j^ݝַW͠iE\3gmYz@.r naiUDyWrz;NNO&3|qs`DOfVmR뱶)TUh$xW(̢xhuW 7GjC?5ĭY4SR%̒uײ*хFxb Es{&M#CBv33Ro i3 _+6*Y3 \Gv ,yGӽ0?W2^XtaӥƣRѹFqo Sڤk82(OmEʹU `pHi55ƒk6v#rZ"=;ㆫrhX P)q seJ ^sF''`ĹK=F;ցNpQ:V~E5/O2"?3q(voU9~c!fD%)F $Jii)ml4,1[E7UFLũ;TLݴqB߆Ap^E0vEz\p( y%⥭1&tMs}"uT/~$HdH)42Ѱ&vHFA(4_>\{٧>i?/QɝHwN>E\ ȅ…- "O\7׽sӆ=k+驮O_ mKTU4PJ42#:8;/NU(afv1<usz d<vEGV RVNU8 7ٙ {^ѮMAz+ө}%b :T.prO~m6r_OiWos]~H/{65̳KXkLEa m\TF~(RاjxgU50SEg v{)T8/庇@=7ܙ^ 9{촳6Q7x&Md).d m{,o44M6Ek je K9+[9,q0&8E+!XmG&+t?qp׼im} _C=# W. c&>uy cnI ,HJY~+O@}yv ?mߋ!)j SH*w}M49hks˘7BƷe"a%^A!Lۈ4ԩ]"i vҬl&'ƥ$&iܸ >MkȘnϳK_pq:x0@ $ *F>\(fУ;UgC7g-qif KlMJԈQ4TRTY I riS^_sg٥}{iqת3o-1UE jNp,̰x.Ή>ZI^^{f 0,ՓDЩ@5@1. X$= Φ {L_† o,֝.-|tE"m>0*|'.],3Q"҄%l-,7<ȣc~L;n;t[rrLڄ!8OD흽p$WT4˃ay8lv%j4d}r<hNHgũ`,}0VMdLnx#kTt8c2/[&ԢT^'+OI RRUI1PH桪s@8N:cbMG5FiZ뻮NMJ:tR$HQ^B.x B!>P#T[]toc?ӥ>pE Frz$V-jl&$%iYTКu+A';W3IL)]x)D"t6,~`V[=CyG; ڊ>w3=UI=^4Gv^ݔ쉀'І亠T0n"{ p^AI$Lu_NlK?n/O]_t} `>iLƀ}En'="ꬹot .2!sat|N7>v3! gIN 8b'*fNQVcȋz#ff氌Q.+TOXRpsfU< GZ~Z[&8In |u"{8 wAr/|2ZV5 WD^$*m&@Z"I%>Q \KcD4T<`VRUHו35.(aCA$ A5/+'}aZ:GkMn:p$J&)1Q%W\,Pإ~r@ϏNy5D%&ZefqT` P2 @{/TN}pfRAŃ:_?vM _sǞ_`J2jNQh[h9"]ݧ{"Lv "S )+B@b|J̉e4g#{K/OVcٕ"[hDxXq}!b<۬O" PUqLZV٢3(SPL 感ed{0v,`rypW%N*Ѝ|ޮA'yco)70I=VKk9pGv& -A\ԕҨA˾O\A( C_I.ghM#~`j\sJMqEpU/TK"oHTR qmT#&-q6Rm{u<^ x̘8jJ$T349h PQ 1qLLoes$ex Q+vxJK&q]ʤdc1,nv FdU̳ "Hn[?f4ű·S=/2ܒ8}we(a>dd7\=jOr‹zR2;BMŜj9lCT(ƒl ;-_J:X;r:DP3]:U r? )QZ[> ;ձ $v@_kL݅,'w~QF7nsL:͛X(3Gq=x Wnp x>N:*v[,/}⣚ P YpiY2 ɴY41'^ }<с.\t}:S\P"a)RKA5nGmd[VschWX  9oJ̆ x! G6ߞ] +4(Ӏ-iQ2ZjY5 Շf-ӻ[˝3{ JV9VD>x>zUx9\׍R/EE96!Vu- Ya84 n"غd\>m3+*˗i&CTr&W0hw}pߢb %[,e:+NI;5Nv*n^'wwgĘ ,E_i:c1TOz+gՊiP-dAFlU"~X`/?6쵉$l]N]Yu5V^{>/e9b1VgQM1pm2l#E˟>1B13[*]wv^B8q!R"R<䓜<<^~ 0<]UG5/w 0/V8fb A\XZ_ܴd89P4XYbUGok븑D2Hm{[!$}rY kAhş[.j9{voyot…f{ǦOJ_ܐl2gwѮ6Ig*D>%m;ؔ3ysw( pSC I!O8ќLy4.%=pqF[3r EUz]Bj Ԕ|Rb7geahmmbFc%شxK8teeg }98VB4zڞ)Kaŏo0o^<+ʶ}3@mӶ@]8綮~"4-qI^ԓ -g| ӻ ZaLeB}I7-gl JX<͘a,)߭ZcLWrN/oS}I"% ˿j}'~Eo2zbʛaHD zgX}F 8q>O-'ޏ^^v:1&d]?-: }zX.|2du{D^+Ėj` 3#yrbѠ;HbOءɊܮ >^OuIi:4gkr^9}X:&ƦE( BP1}$ JW)]ȿ Ts7~t%/DRTLOxY*Eo,~[g*bvFĞzܓ} Ta.G A",`h ) Y+m<]s;grT=dz~!ЈUAR|a5D]$B2^"uH'k' \TT ЀKrYy[tu 6ljwTVdy4*NVlWи*@*=[(> 3 q_zo#k4|jb/&T`*}]lz̉/,0 V#csBS@%X=g7@tHy 12e|CjupoXe҄bznݻ"_ fv.[@37ga$wrXΠB~IXrh}5Fs^?P䰰K9qaVk-|^Zנ(赂}DatJɟ~Z爐"6wZHM5,JZ+^mwNf 3O`m@D:baPGrqok*x|\WPF7+k KG] ^"Fy9v2C 6C>67K&_v;hM i]K85u=nD-$oC]il6 q-Ȕ'Ad߈vLO Φ1ee6E)/8OV# /y~et H8r.n&c }cAq}Es^7T"yE1Ko}EͯWd'Y\>/k -,LX(LyC0R>-;|z`sF/2Mmu(ϕXc&5Mp&:m%dC~-o[WgD ȵCbj\ߡeLU5kn$_ϑDT?$RxJRA|)/I+2"@nNN'CN1c(~޲{}+֒Ohuܜv 49ޚjŶϻ߻%?fH" ̲'%~~dןIr HClQR]dh5g"]:w18}h7+/3@j ua~PMIdxV_Z]37ɮރ%H n>1IJ1&.P<W3FO훝O7kDoTSSou!|EzŗC?E[Po#uzI-d>dKwK}4rVˣqYxQ@ߒ܍ uI8qVmr@Naۼ:Mbrݬv-4@Nmzs nmϛF15y s*@˿{sN*_U RU);ZpH*ũ йH52;[!|;KNfZh*Vq# >:\Xͫ:1$x^'i|1>:!b:f|hi F{2n4vZr7z1Bl5QEsyd)RB_mހ.GhӐE {yZ}3CCS r@m&T {*ti̘QT?)V߶v$ZgjW  .Ljad3s#?nUl;B-A͌pWC8&k쒶e,r)P?r{gKw z =oENxވ A⣞^n!460eȒGXKyW)N瀺*i'L\=zW6KTO@h5Z| ;emĩF݊1q4~y;d~.٩ͥ@vA0Q8e)mUz968j/JF1ǿwrx_*Әrw{e1]c_e:?%,2*183cM,*1!9(rkZ[qځ)4T IuBB6oNglO1e~Bpk7M4Oo&3hhTĠ)/T3:N*P&0zUK30)-K6,yGdʎXcЍpٴ5P! ൮dY LuīRon0%IKDB;P1~1ʎ^6vхT]"` ZX+)RjJm+=ɧ@ѠdHOʝ\e3foEXq> !f:z:r! LDAўHΘ&2h;-Fzɨ Q/,gV *Sє𥉉>gոIy2ȁ]Jf"jD*[ z,]?L_IOp+ W~.*/|K Xq7o`k J͋儱 y3+(J~mXei]D3FZts8s?{ou$"}.]pc7܊mvٻfx YjaΜ6 ZVl6S喂#]!?>Ϩ] V_tinAM$ﳇť!xh|0sQpx?p"йz]d̥@$q$9{1Qjd&#O19g(P1R9NwßWDRek\Hqo6Z_)}{tf@h>>1aD>Yx7@Hp*ө>%qG7Cr&kd|Q6g~7у&$=e[|#bcR3P[)_wo-ν45|?X^S%͹FSIB»B4&K+Z.NRUfv4Y G=n xɤ6ّktFl=_D;y;NYٖaH}oz wyAɗDixAbR' ٽx)G|=Pd6pQ,M°[Y3Qʌ HF̍#ޜѦyQn7wܑڵr┏.V =}cI˔ZVT,Q&<^#?"> 2d!o^FlD-ޒHd,?fHmuS* I{,찆O\!3W9PMX_  JˇB_©=='ܐ1~i&Oj lK#|Jgyutלx?^K0u其 ι61c T 6l&`/u"mj"Wj axL]hz]Z'>7^aZ8?g@?ܮIl"]?F<ޟpI\@&\|#{;$OܥwG78Y\@tbml܊T{%>sY31ǃI2;RP}j\Ŕu$i6Q0뤥OgX䊈c:`6PJ7U9ݞ ;ikiI}g*@E5$2֌?{4qaʡ m 1{7>4uLcs0]OwȽ(_-qǍ}#ρ[yZ< `PGI)5)$5 = q GEiHõ`y<08je&1EoFAeoKGk nhW^~-9tVzIhiz"qbsh\jUqF衖.i>:X 9XȖV3y(O~YAkӊ - Sg͏4`Jb*)Ezmd E {J$hk9wQ /,%Tosm!mݪX\2K*.5Ʃ]!!gG0inT`$L RAQ2@ <%TVWIMkVQF;Nqr&~Fel/Ɨ{\':7V)%=|YX% =TH0 HTǕP|o|ł#\J&k^4g~>.,AeNg1I#f '2;lBv{HWD|AE E<yH.H\nEiIȭQ;SL|}-gܡJZ/={n}/UĪNӦWv(yaf adY*hec6%ߛGbs^vAX8בb`HRVբ|X _ N(%fKLPYB o]vxR^1ƩWhnj }vwY/nT}mUy /:B EDDF1ukHĔsb[sR-` MPiɇMf8{3Ԡ!?*<4k- TXS1,&[ڠ@ 11S8f G>ڜEK]/βSHֽ]7 LT(XS{x S0zlC1dڰ]jJ ӕ$o$aR1zy=OCR@3pQAQr< nSP 0F0a1鈣]HYiq8կZ4D.L ų+מH̕k`+4+Rcӂ/8ܧ)HFGGVvل/gQ `}qQw=O=sreNl<G?ٖoX8nM˥Ǚ5.(C) )__T6~=? ,MqLo!5iڈԜFaWm zKY8}V !*#N@o ёx}!K""^ҷty@bZO0Bڤ|$@SIܒ(E!@`D܎5N 垙pJB+~8Nc84;6EuGr%1}(ʥ('1(Ϙk, \ TmUT1В@ m Oo3N4IOO&-)O(5mN"ށFr{ͦC@ZE9[V>3>Lih em*INicwUP9kaQĔ H§%Y 1D6\2t;(yE ~.Ʈ,'a :섭=4ZUN>*mM~yP}>[?Z}]\ MEZ)HS,0O>#9,&I3EfVa)5PF˜vV ꭋÏ4X{p!cC*/8fެ2 $`{q9qX-TuqHA:x?98_l%ngj I>&gQk sX!KkAh S*1(RjM:*֡ACp?~lڎJѫEZ>ow.ԌԭfF.4"溧UҞqK"qE[د[wg6^N o*q*lp_[G\~P8F"3}n8?}Zn3`RCWR`*`21>eڨ/$lp>N udzbǩ걃 !TINWA\UWsbPK}]]^Wms2)&})JZBRjL(NT8VÎV 9:fk0uJzTMaIS9m~D%=c3FeF*C D܌=RK;!8`̖\bfc!ғx.i QŎ\D4xA|,U!=}o2g%{eN-5S6=GRe|?.hw^fE}d.:9޴Åz\0$J?ojW $pHR<ѹV ۵,n8!dC[Ay3ut\٦rE*٤A oGNn:+ ޟC3T.\~3͜k ?uʋWֱ!^BI8CR{感 wz{&aZB$DWYYgu-\JbV3n/Uvnֈ'R 쏢U'}x]*&LGcdꫯ>τ[ F؟/,n|06'OHqƬc2钳+$$d Dd9[/`ι]#e跎]X =01ٍcC- ? =F.}q?$ ye>ȓD0F@᰻w~MiD!-|F}FH@kTa}mI02x|/fP2PLjۺfN{91 Z){i8#dʹ| )4Ⱥ.c&E˳I.ԞvqX *fe{.oJkT(1m$b<<֥qQ1 ɠ@0mx:xajd7&i >SΘ0JȷF)| a^vЙx*1`z(TelcۚHs+:zŲ\ avG}Od#~´mYUȭ> GFzC !>n~o[GY[(Xf¾{F"! lSњd[W#Kߥߙ$4K*87,Gʟ h—y Шmh(&J8>A#1>Zٺ(x\Oq[ts;$ VM홙jZjak}?XƧ5lHziKX_J+ '異j&q)ƃGO)\5 ؉mFVWD%Hl|tY?+CL@^J61VcF-buMzh_%YWYú'犼"mnk3ʋ'}W+T3ȅP~v~TZT̺[F4>QVuƙO-Ϗ8Qұ(t '/߳ϵV&XY7KO}zHw㖳S& 84^Et{ W[l8)IQQLGIɣuKK@jX ^DXt 3]3VsA[C>s7%QA?~5"ݔaW@6ĽNT6=3HLQ6(TΉΟTAö^OkYMf߁,"#́D=j贾3+5c0۵Qt*9 =Vt} A-g x*~VrPGY.GsW,ݛ3t,[Mh$t [rzAa 鴮@%8(v"XAlmTjh,`oN a6ZH{AĈ~uM~X9-^ .KEe.)ٰle`fk/,.,W+]*4K~=h.FOV[,߾O +D6A8H\1?Nby:y` FyѐQ"M&{y<8#t ,0CIEsP9ʁzq=wi'\g\b;'i V7*TD<'#i-ɬXlpO+dq;] Sr;nzXA%nؚ"Hqt( gˣ\v+5~Yp2OFi"Nuz#/ {j,ȥ݄[h,E2 өwn=ď\^MaE$*6Eړ*cmֻNb.mu}QDڈ%%_B765,\NeX\1Re]o Xe7#at u\i~bߢlS{sNezQԥǡ/x `{5!wL%'+CiQ{7 ΂$mY CQz<t5:] ڲv ސL :E>>0սFD0GoI&Qs'xiV-#E^ޅi3b n@qw  ٙW)kŠqqJ/'$Ƹ6Iا6+˥Fuuw4O.wC^.C(:h([1N}Au2`TBG?\L)aZ: vς4wвMa&x; Y'*"p]%EKkz8ӂ3^~/ [kyS˱@TYI])# {#`WL,&δ1j"Oc.=5l9 'ڴM^ExFZ:]e58owp0Qs{<4oEM'Oƈ9]4v8-f^U\Qs׌2s?˾2lͅ{y_Q%oYVqC"~Q/k,1iPRrRJE0꿫cNVa);Kv]N )LƄE7l.d>60n1e)**E\ ቱ7]_.LCf4M%$isIq[ .Q3Ŵ^j`dݚhV܋0ݠp$ך~Vƥ#)>DCEOMߣZN&pi۶ xZAo{iyON 3'ek BWL! 0hU)M`֦Kj{,ޏy2$-kWo*jP`Ӗi"ũٵE]dCF:bT˜dZG\ֶShE4ȵaH J $MLwIxAU-f?-alQ= EǗ:`N6ps(2k/@аt1fBӠԉ^&m6#;蹹"O|j83AXȃGi|pc⦹mޓhds=3>+-7{yI~@mEHl8czJ V*0cFL$ QΒ9-Σ4WcW7^+47aaO*7 9~UAO)"'z&'TZOIz_ނn`x&B**KcNzKp<W(r эPqi׍Q/?Hv=%KLj<|{+DpXhV𭑼)G_;pIǖ|dz]Ud mNgܔVdUVV/5|_c>/'j[ՕAx{ө{Y[88ὺ{ZBu?1XB1G8YT&b;; ˬ4l1 ?G?a>e;(q"m}o)hnQk-ynNimdsuϤݶKJfW\hX>.x/~" w6 CfAL>l5`{<(.M˔'+OM3ޡ#[ïq ftȦT"!$K!B 4bӱBp,8NJm*}ڛфY`0SmU6_ʇ3W­D[/&lQp< |]!'i,^юi&Sd Z0+ɡOqDK32 Wv_QB%X>R (}([ 'y:g˳o!9íÝuurCܶCG@3.|w$f Dw-DA^т>*J?5@6- %3j;lf!vmG{3\x(,Ȧc)+R=mUV@HwY[e1hGRI8ˆvXvCT`)tѰƹ㡼D;&;;3`2S|=e,A3PDK$xNh؅ށD|XJ[YNJ ͹'pcv_^5jsZ;O<12Ug$Y;}=J;_Eot0*^Quͣ."DeS?@y;S4ޖuAvXS&n~*EF⬰eJSxa'S ysv+'^x*R={NTSg:*oi}Qft~lQoR`,s$ Amwvpqo&zMo8br.}~?ུ㔏S273`Vvi1OX 2q˔LU. a'h]32֤RqJ߷= ?}N% v/đ¿Vg⎯#-r NWՇ y^t2 Cp$PZ ԦU79gHVC.3"mg6!Ϸ2-BG,sXeS#I Oj01PS]0qz=;SjޙeBLϓ-%y@5~]6_C=r9h'ŪN)` dVG(YVCz߮F`|]87QJ<b %X KIe_B@V]i+AP_:XZأ:,=q~E)f1"q $4ƖJW;#[D?oF6ҜԘ>-=Ťqϐhnɋ\@{7Ԉr"}-Xˠ蓮o VlIl}P>BȤp$ϗZܥgv8ga_~ lSقDu6 ٌT$qEԓ^ʠR. d|Ï({}HĚ8WSԔ[E_! 6_m(z$\qQQܩGօhT$C@:juAgg@/S1A|P{AU^:aR.@ѷ6{; rv=Kt-#ϽW'į}CDLNcWgLJ^՜ZQ|L7,tnױ0ZE~Ye/;"s '/`&[8\⎣+pbl.%=W~/!h( [޴ZcS/~_u8U2E 41dUNMRpc-#y+ɻS}'҇$v! p7RR?xHeT,˥7vV+V4>ӟxJM+Bا!kp3٧ y {D'zS3[D9zeEf@BF٣y9]nԨT>]E]ǎ7(I8Vءӹ 1ѡBL#ߤSFeWz唓;@t@U5DP;m]Yb~VcMtTe~WP?i%3C2rպbq[f| ,I$d׆+k50ݩ}*W Vv8dzf퉐G9܃nntݐDw`^#];7{(p/lj{ @VTAR9(|ꎚSՍ pc3+iJ1ku84n>z1[]MD]+s0F>&qQ\ s[1nށ;\m,R}{~!cOྶh\]q*ѿlܔ9٭{P5('t .AqgG3ݭ?&l=]}dXȠofYiZZ*O̿ܩ??VNQK-V"M?t[O"h5Jtt(0hcŽ`bGZ›Wb7y2 fkWo,jş[G,׃:_>80,0bij>c&(ֿ0D+E"jfw|6A1!޲K╣;oa#8Ld , Tݞ2N8oOf>N4d݂zD6јLYc+aB?&y71UM=v$(.o/L D*>"iy \dʒdl-!_uY4!]'.~M[w:Vbw?޳/2 &lY-GO "v"4|1p2ڛeDvSe.16ܘ~\/q lǕ3 #Az:`Z L͵&"꜔qa& LFإu#"t[?@7PPFưUqecXa*KdYhԗ?L#F^:+ žRm !cM'tn迩o`rs`RRf?!5lfex9ž-&&T,q?(\rcfU-.;+#{9E \NTD|^6$"@dP W|KȽ&OqTKBXt?"R~1@l֬)eH)~7RFXPab_-]NVά.<̟/ V, sK+]Om NΚ+҈]`yRyLO{bw04MWjp$xXXί9FdSgoE;u:)څ|[O:2%@$n -h[:k5^ϩZ ^rA@|odZo]no9–~1JKCSRl]%XkÇr`\%Q͑=_^M8nRjum7}bXʋ(;@Zn[BA(qe`2Cd.%LwA 'F Lv1Y.ETI1ɜ}+y y d!21lZ/ ]?%؇}‰0u,{.XX^$OTFІib: L4Ŷ 擵CR9ib$8ױ9}IG>6rGaΪ @+l}Pyq[q0L=s\`Jp"=:qH4/>1(sB|i~đ|n c¬ƪ{uyQQ}| xgQ. 51l|RHÑؖ+iμBZL``xSD3% j";6 hL!GW&5C/uo'K×ՐN[b% x3k ;s Ζ"@fGU"A==5*I)A| +ۤ?^e2_JTBlwdwrV 3TGɥz8O4vM3,w(%T@+IKS9hTXŕsf,p+ :| yS u)\" Qʭ7% 3+:)7ݯe>W"])tSŲD .ۢ 0Tw_3he DRQ;A'،vTwH9}c IDX> 3]:'"3*^"AaAd6|Tr}q*l -lQZDfvÊ*e@Z9nj0`dD;\=<mx^Q5͒Z7,Й'P8ɕ6ȥ[l EPmkm@̥6Y{V5 R4WNv;t|R$M0(+lX"5Ql'i;We:#²*z)d!o{b;\08^v\'0d?FBcm $:-lߙnP =ez"U%=Y_P"4Ԇol2F҈ /F*%dY>m*@}RtaB  HxJ}Nr/_PaHTƛy =r%[!-4rL`S$)1\n/t^)ICf" /bURI"z;W:1@Sb;!(U@}Qq-FhH$O<-[i]Y_kh0g w-`sݫCߵps$; XdG\frjsBcY%B i86nTVr4Lœݼz Itzm֪9DTLհTe?_$, 'W ӱ(~ '=UQ}Uee#cL*# 8a04+kX<*d>N*tqR9-27j13| µdѝ҈)j[B,%Fpe\p3z~JWM;d=jLB&wL%̴uZ*sbV݅`~61_Y}^nbo(WNxtZucjTHaLAWڿ#-y(24 ![>ۣ#."ڍȊm2G+W"x[Vѡx4y=UЭ3pҲA9! ?}e*2DV4y%pE̋\Kd;C=P/z%f[1ۙF(c)&K%#h?o:А~6cŠ1r\xFw:gokDkHRM[D >3UH(> p.T~/vs]ބZT2hcJDusb:z|hIL%&Ů7p:p0F'ae.f!0۔-5?K#Kig|Oy!G qФV+!DkM&]* +dnbuҗ@N>3 @6Fp^Dz@:<\R%36Gմta{h[mo;UH!TIg=ϊcП+z.)*Xwf:^x8bz{Rbׯ@Y5AٗX"b =Þ Eziq6uF԰)H;.ciAu\t0&([>kfԎ'CRĐ pGcJ 퐈2a`DqV%hi@/$lȝƢWZr.ڀffUȊ!)=c4dp9 4[檍vnYJs௜fF1c۾@b Z^B#q=%t)Щ/2}*[/;M9 'm.Hz7iuezg ԸZZS\W,.U[I* m UpZ\mvM1DLϣ,oҩ GG"w|\e1 Du> 2%aDS~OO<'KȬd` 7+(A9%Gl>noYSGx^(~ iLS>S'= 7:Qx#[/ߟNb^ VUd$k-Kh`v=Y͐GVQ.pe+_5Q2#f{ .jceQyA x3mjOhY.Ql (#dyDԭ"_q88zDuj'wH//w~50lGUĥQJ.V8Ƚ@2l}YJKJЦO`D]_}1=n>RD,8kYt7ͷj%vng02+1>bZ>qբU!6Ƿ PG]q#nBߨ]0"ʙH8L~R9ߩWi1 }Ut҆䜐M04&||R# Xd ~M+xW©exo36_aTGعc!WJK-`MRf ;"b!2ustXh_?#Xa!7iM*ܤ1фpMYK:YE#~wzM&fj?R{KW$x!5c槍=0WG:qCjm#?Nf&Y~=?ԫp*nKO5Xp O6Ֆ786AB>ibhv$`NPy7ZO?L"ygDR],Q9gOEt@_7TA( 1;†! ±GŨ&[^R0ߝGHi=2[@F fo|Tش0T{!yϚ'j(w߮]vGIIh 7% Vx:٥I,\M OeY Ȼx6dWI rWKI@ƯmWtEIJNUS:lA)G)FGU2$;Wlh/L g½i,;d:&bvBFc5ͥdQni8d;t \eCm(4KiiĻ^ƫ` 68LYU+SgMwx5}u`#H 8I:y]t*{X-&J wsG+TA&:;U_ıp/|ڿ_o=b.V@%5 |+GpŶo* !s2J+1i̹2yjt8xYͳג")dj풀"GmLMeLy`ah-˸|Q&YҔe [JzFu ֈ:P,I2ȷ bvH)rpX8)[s43-{'+@l7dɗX\ֲD<,/Ĕ.'73@~ H!ii-d7V:{'d hR`y5דQ Mc}iOŜorZI!_MXȮ ,(u)j; 5< RFzK%zM o`,iuȘέ׃Rc˸Hdp&b4d:|oFj-V5+9!7QwD>V? @'k8xz-K7!zsݑ;̦:P?$28DJTBβS?he~Ȭ]ƹ+f8B5pۍs]BZhSP |yث[=oM!m# vqHmE3aNSeȟh!XϏx?TW;n[5)^aΦ&  ҵ2_1o&y}ʇ+UvZq~e0#:e "$y#[>vwM*@3gUl! ؇Fl[CW^%Z=,Ŀkb@Ee1և)X@S6gLh#@Mgatr?/!2>ktWX\ nL<gev+zzӿ<)1[7E)J|:+{P-䒿(v92wJzdEc`l/쬵xEMjiWعu#u`@x N)3AL znDb.^(Εn|@-kcO &5H~;`+2] RWz8@~zPjW*-2k^k"p yУЅ^Jig{%G g:̜̔@Et"[MӞ&Hډ"==-ZG/941>dzU!Xh'ڑ?)]g)[(~ݡ*zv&zHAu{DvD H |ۭ~Q)Cpm?)q7]2l9.L)l:)ufE[:L)b.CqnΕXA 9yE@gݷ&? ah* _w7iϥ#yAzw9SAQG8ajz3F0(чY/~Hncy5!Op׮z]&Zmfu2X`aK D74Rܯk]м*T܀j3jG˒cbm_P?3Nn2=)a-񥫍U"Lb}`YU ^|{}Ք/pOCr>fs!Jġ\ W*xjJfzRU{ Ȇmx\_VBXuEU :Ш vwpرjETT63 :(Q'Ȅ(׉) dkO(5Q#DF.<5Gcϖ聽w_=IL6Mz.;q2">8X>ݖJ^1o;@Qonc6<yRBVt9R4ƾ=7a':w\+yl#[&T"HnJ[ tp827Hr-v>ؠRm9"}L *-"ܹQ@wiK=5t,Wo' Pǜ`81i:|CGq><?pz eEWg#eҺe%!ҭ#pU4Jl,|GZO.e1Y5}ψ+\EyFAs*I:l߼ڮ5vMbbͣ!fC+E<a^l ײ{PjHL{ Ep'<(lIBhcp}-]!*\Z]MKɥU+\+0%A)J~4J. ^uhAfٕ,l1D$!Mq_Vig[JOb"nCGb+*L/-d7-5yӗ(rN_mͿb.6cϡDÓXwd}3~BrGV_z^!٭`ܯ!WZuvSj91Wb$kzqI)wM 5K,5,h絶݃mxSz5R<1Xp/O0cIG0Q r+yHd8Fٽ\.l ZETUnM3Qk/v\̡Y8 ȝ#t.t( "C @D $i,Wr:(.` a0X56 |R.5Cz LaOCËR1LmLbK k :U~bCF2v 7JZ"VZU9^5m =JÚ83-K J洛0(bվ)WTKsb4JmC5!XQlj]v_#Tq :-!жǕ\iuL ֬.#ݱLQ[ Z2&ԠX؁~C6  hŭxͺkh9UuH3muMn}?ҶoVف!CpQ(q . ]?}Y[-orFѨ"Ai `βl=ftO䱨d3g&v5U}-k[ހ3l} Ře1$΂CO8nnµt4Qh_ywz51Iiµz;T1-J/ ]Y샥뼌!k#iž3hwy)grE7j~nN痿'~rUÜFI>:б t) u# vWMO5Rٵs!c@Jr1tRl|Y0; qVO qǀz9/ύ4׿|.8/ (>C"ef%7%g),RΟB.p_[v o5/̒`Pj5b~P@,o-$T A+ @#qQ6X=O[j״j'˩ZSkVᒟNY21hA&2>8^*h_J6z"@9m@dz6o[<]=NF)Ɇw #nץ[އ%Z)w  JEf6/65){qJu3'K&~ίUpJ.)1bYƺNH>kENK_?2riEMǝߐ+͜puo[/Q?Ra3 :ٰdPB)S:eF%ׅ20IEޛ ܦ?+ޗG6=ޞiqǵfę9!8nn+h>oI|׭Ak<}@w6^ Ap\%E~ᅣ TB!=, CzAcO Y&@UEPլ> !|s K1Q}eIUaSج pgȎ=;t2)u*6.=$Rtxx%X ImbE%gsZݹ[fnA0^DExC/W<\t[Ʈ`h!(Ē~VFI[Qa09VB^߶ׇ:pDӎspzdyVEK E1q`qM۞..Շ^S\*N.+[BV/l_L CN@0?&]MIKw}1s1QLa![$fJyJax@UVCN(dQa2C@-ժ#Zn$+ukA/5+|%mcFimykA-GuQRu]e HѤHq{j,zxbnQ%BGAh%}GdҌ @ˆvb8|2ӺcKjV0fП m["I}D\|u4֯/ i>LEl!V#+@m"en8,wb.-¥KxO+.E[w̩W.M2 dhfءdԄ.VAk-w|WZ^DIQ/f V\ڟQib\xf$_\h > LɗYԠ~Es}IY0*XIN >{qHc^ kv Qa: 1xL+-b}棧Uy6ikCAcW{*e4q=NA I2NMj9lB7ܼ>Nɭr(p\^@>ꌨJˇ(w< t0OKӿ+.' *$_QH Ѻ=]zv6G;a'ЕA'tN?VGkB[ꈩڸM rXY+9@+ރr6XƌqRMx!d_-|$aG"sR*&:SK(L~녺 Va%cp%h@^woaE#|.g]-]%>H-Iwy*k׻j6 (/`ف=47<fwA|D]]F2B#R=: EJa9I`W0 @ʓgsNא#k( Rx*=T緑hW:N7<&(wb}͟(,4aAR*剀K$^I՞Hig衠|o~j()nEMФrJԵ/4eY-N9kv@5 7*k܄OIan6hP q=@Cc,:FEI+*\x4Q6x9/eGzwkps+`%O7U8j*M)uW٭#,[BΠrUI"VFUv*TQ~: _chSRVQ =nPC 08BDLfgeޤ:8InA3 ȍiOEy_G%04QnsX0Ey[*[Z2?o>Wܐiөͬ-gqצۤ}0tڞ >σ07Ÿ“Xv㴟=tNP};'Cov)Ѱh2-Oe3v=?l :(;+)Hf5~}U0Z_#ExnŠÈ3Ihra@dȨO|VR?66> RmΛԷY҇xG#|ݐI--k1/H cb es$"Ļ<%)A"ܪY& =̰97p\V*ܽ r' G&?PoJRtT@]w RsLF <rJb>Hꈂ.5?Syg_ ,FP8Vmko^}_M TGmVHfsV0C#@՝F(bqH 7ǁ'ǃ/(l,Lvk*5FdpOqWOpr%e@\uWI l" d6e,Y k+|j ⧐cjֿ-[C G𷍼 1nw$ (h6Cx z(YHzQ||w.$7 &\Ӧ%xvdg3bW]k t3'v@zx~yXLd`>eC$/{:.Rޡ>A),ÿFhiYi_a`#u bh3+q}&A/V;@Tm/4¸cfZ[ ]8Ǚ<ծ{`W`UT} S9q#t?ᓜ3~NtBOm 8F'j/9AÁ5e]a#ƅƕO0sЙ2&OaO0*5u 7@~]<ng;K#y?Fӷ!8|8&RND3oOKɶ]EdW?JL[49Svq5qh'& ^)gȽ~(RNi2$=.k >{/Bs}9P5[A[Ih1+xpyd* =}AAGa'GGl4ҷ-2J⢹%% }nDu;<{-><.>=dHBi{ R+?lT@B ץX~W~, .wlUߦjqer1aɘj?M'zIX0d쳸}8J_TBO_+Eh[Gi )wDʺz[ܔ^q.تAޯҺcD>Ю2rĥRFHAlg$LЩUcm'0{BQ'PX,L_,aNƒs.o/7{ywPTgݎ懢K*ѓg6XOAh{Sʈp\rXvgPvL>$c|`n)ly$.9AB)'Y@ $ NHB;Vvι R^9A Y z)L}BoA!2'nMMk](įQ:!/Lc.ނ!H/!/th QWfڰBQȜ.Sڵ7&h ; #d)";$v ދtdzò2;4M%F *-H o]@"A ȡ'jv}y X$ڰ8ni3CB΄W4R elx  Pz˔½aXPAθ1QUU[ܼ;t[Y]{fo$@Ci+.H#BLqg{7ƨҢ M{;J+j1frfH*7T^q~[Ϣ d-#-.t9NKCΓ |8I>!hl=VcŁ&>(Dh,<;Um…+0nEږ1fڄU^fM|k|\`7ٻ9Y2 +Ctu.hc!a&N3"t9˂ߘh%1'a/L<|AEwkuӯ2"dPMk^x53B]Z@+>K1FP,L9Hoc?#4K{l|x){lPZ/q\aB&.Ris~P]+J#x rQNYm`H>@d}Y$2khre/C~㡳M& $3`L5ǘ#:e;@q;|{$&(,h*7{ RV'ˬ+qv}jfz3٤# }EQ*w "ͣm"򊱁O}$ZY2j<.{ p-Y䑯h9ph5:jLE}Lto8ߕ/?4!$ kv U!*C.(8{ur=uxZCɋtK\8\(tu?zb!} 7YճJOWNKt.D>1FAA!}[D[ŸhD]sګHHKsfUcwVh;-'ꇊbUΪ˕ZX9#|HT!蝊!E8)|牏xFn8 -\#RHSbDrF1Ro/6ҺvjvEIB>-̶h.G۩Cߋ?B$ \?ETo$DwM)8#ұy™5uf H S7 ,-1>99/[-qq$`_+F('EcE$.R,Fh V_cdFr~SJk5̵ ^yF>g87mҪ[1; oEZ(:]r>|K@c\Y)#,2 KncGCVa^/?Wj>1Y5?ͨS1[ili/>,,V" F 6#APh- &[~- `>jEb F,qvh 0Q- %Ta7ʜauEc{B)cLك!y & ʙƸJdZ3w*ɗ|o|71#zA)U7٠;I!o75'כ@'QȉCzvm2K=&⡍5glNTBgRS"KXf-KAi^ZiB#@)4xSW+$_9#I$T`3 \S\).Br QJ{@|Ikk+ng]`'a<SrO'B1J#Z9Ћ b_Veн=_, f5kaCeXTG+2URfS<&Q|- ', /A\ T&e|ymi־}P**J֞Bb&́&N#"+T_Y˃q-4X%gmJQ'1DKֻ0oh ߏ t= csݬ 7^93mQqѓE|g(&ݱ.H5E⥨^OTa:\r,E;Fu71#q<|,ϵ)Ɔ6{O:}NWCĚTo[(ۏOڍLYyb M.Jŗ͕`V\Guq4|NEJSCO 8XRRH[F=w?Zz8j}?ᭅ$r ZYdܺ}MB0!`)mҠl&؇HH,DBzK]MFXԛZ&34]"LIa@ѷjtI'hE3L35us+o:ӿ넨uqva.nBkTwY@eEnb¤1 5TCkw]\vl?,i&P4{Dz 9M5 ~Zt?KDS/5 ^w!( |`.;jd3qti >.i$abQnﴁt-0#P|6[_T~{'#dT(dcYSTB>~}fJd  7yͤ?A%Vps.x ](k "sl8Md-U:s[2{O"v*Efb*/)\QHߌ!z/T[YI%2T!OѩԄ;_HGObogvwD݋zkjjGSz{X))ȱ,}reW@>_;-]:'3ץV֬i'ZNB T!Txob kXvP:]216Yv]*eu}_3ӷ3 mæ-3?\%!y3@<'^ ygs^G5ogxӧ{B2}E=Bbh2"Pǜ|7`)<nָ ß%su!ETo2wiO:)j .z^kX"jVkdP`c^"5A|&O ^lf SmAjqU4~Bic*w"È^|ijq?3D#yt'$&bbր)A5&aĐ=whΨElJ2h.ItW\)Uk5nR˧} 5zacpsmY"]jڀpM}s G%Oir3bqpܨԛmU)]oJpı.xAܬj ]pр!fSt `.=#2f=0 }pP|ԪӠG9[} E&{:ꛖSpx?7ץ8襺.t>pZEkU{|y}sy#WqK.rvˉ VcS70WcV鶴Dc )_%/+:s}`NM&{9 meSJJzҳwޖx[ r4hIlja))ܩdVK3B"@,K/.mAx`UհY/@,OHؠ aL{,ի=*S77Esp=dZ턹>=Re4.;& jQ6 &OQCG)m%%mTA4qx}LO^s}4dk )eNSEZ$[hǺ4G'D+!(4khPu./Y0.9 HB%|Rᔎ[KV@#`KMRhnncPoݵ3}]TTA禣9"JxAPhEbjœи^;GrwC ~h!)yy`}*_Y/vP[z}w#yCXXpn&i*rHtjzlK4 A(勒k sJ *7.h ɛ;\@ ìV4ݠ_3.Ig/+S+G cj"$J3NBxm[.Hd=M A7pϼY1ʸQμ@-?\W Y޵A _\V_`FZ 8ƴ6з15I|s}/HtjuL0RCB (n~~zD:Vգu8DVX0S (8/_Qڶ"0X 2A>ܥw &'(vxy^i}}Bb{#<.1 T#7AHPNg:!wSX Aa!->`͌l5%.T91?nk k s6,vH<mz'*/F̟4/x P!s #!ǘ#]}M2w*m_)e4݁t%2)L}saˋό!L&#/(j_JX217_]t7aYC8*ۮx<#x&M{? LElW&e"?芀ٔILJhɳN'u@[ DVQ,ѽo~K uO,U;ݜWoUH'^Wz"@:dB+2pL cՠ/cPz؃꺃„;W6d#r{эçVh9Nx.}O+gxV4|"|mY1n;ytKelծjb8%qUW/#ն:h~~ 'ql'ᾐk=lw#H]G=kv{r-Ψ}gphZ(s$O2i7֨ a  scIzZdgO[R2h.%+P2\[d+vWq`Zgה}(8HT{C[&UTp]?"SaܕaL(I믐I+["-f9ك_;;2kf\aK=Myw ;<5AcGP`5Nv gFvE>5Yx:';@Sx$ǑlqP~|tbK2ok92^w5 7c=HxYTD?KyeRT#^JNM۫a+#U,Qߎ21'3 XQVy<0HRPDիaI2&,"YV&{XqYUNsbIZ)dAa$Vf1l3mN~P:xFl1*ny9(FG m}Ap[=`o]}==1AAPvP2}3D,Y'FH,[M#55NU/_?n+hEvg<jR.:I?q [܎(s@þO}$|ԭ :[?zIqc9LE.E!5f*W#+j%dD^@xgλ @lP#ać;S9Q>^=uxMI02%ֹQTؤ~Ɖ,@+C.SFO\qBr1u3Pip{ʚi3S[R @~ f@~Sg LM5mU0ۼI@*_|IAE/Ws2<$)tO!Yʏ8JaI5`ƥ9h.Q'oz`U*?Taޚ..!1ć&5`*&DY8ـDZ'mf4^/U c2G\@g* -0aA \:"敁=)qA(X%,ԑ>Ouwo1Pl={ðHbʼn΂8. Ma_@$;DCVt%x^ފk"]Fbb]a1oaRLn$Eε@EB;h/k D?.ᆷeV'߆ALi 8s1 ,F !ȥȱ~?[)uKa)[Sc)&qߡ0(y`@mNIg_ߌ&_덾:},߽sJfu/G9Y)ٕxH+*U ?\#szC^hRܞ&FJk%&1{NѧeZ*]c= ?F3o07F?ZvZ bUV-eBoPmؽ|Q Vqag$XؙWM=X8uMZ"GM%bTPh'<߉59 cF|;M8]8LEahI 3 Rm="(Wbm)R/=K_hĒ OT`PAݒn)F۲1 X*NNg%J+(XIe jKB$RW08 faWFХAbqf7F윂zfY &`}X'42 5חs;57ÇkVqdNϓ:;Ås&'\t+=ܵ|Ufb(v$j52BA3&\&~t+U"[SIu84 'QI82bW媩WNEϼ^v?eJ'r>i).y9n7>C.OlU36! T۾xjX[7_9e+$׃maynZ4xIgP((|o_L_ TedMUIRڡKi1Œi#v)C̝|52/jGCk_ZDfV'ȓ8st1_|"\<DҰ9ZGG~[_,-ou1mc#Օ@u]f.>\j ^K/Z IqFF9T3@Nmr 璋 hsס"Z;aAx#(<(Z|KO{5\j<(Қ^Q*om9.0)7nr)[@3VNぢKf,@DrCZ3HwIK>D0<ԺFǷzz}xg$ŮuzW{&āId^;dp $d77htHof $1{߷ç?o iKV_dwC6#o `n7c@mNg N˗,0Sq/EDzwmQԔe} 2&(^w|[6eMb> tR Pq_-8Z_kNr{LjKgԭVAP(ڈ癿~?/4gE=U:ߪ=lE6$+m9+0rm=|Fxܵ=V(@_{!%˗,zrp'd'0 0^S{: #B.5"u@~= /0wdž` pl̀(#W^ͽ7[}_67 ) d}Sqѱ[te %db1Ni/~Qs @]{:.g WҾj^žLanwv;$RbJ\M1~bǦgXN`x>)a(+Ӗ8CjP`}LyCh|_3`=ĉfLk$3M`[4 ѯC7Pؐ?vHL5lYthq`ĪmF|wN9փN+uj[\Ja05[2%kl!R쓾[pR+1iT\v0nd] ԣJD ]zY=m|ApCNˀsN6sȟ9 *8&2cc *q(\f߉8W<'5jrd0V%'G(7&qD@s1 ^5]ʔ5r;-뮓-,;_^y[t pEZj>ԝ4o>jڪ!|˞OVMy*TF ӪeȨWZT6;3Sx%{&f]Yn>$@>tii7x-;ˣ\p`YC997ZD%pv h @$+>%F6)((AEÔv3IJnH"ngzhMFjvz$74 fx> ۩yB y2tF7qd0 |d3Dn}^Axɹ?o"i MOO/o{E鵿JJ ""xGv3%B#PÍyRRVI* oAnKgiwCn+eb苷 ~䗢$7]+q\E[Z".b]&YWB4hiωu0oR||M*h2+ۚ*%U*OG f?$*Cfdap`"gwD5%!k{Tt&)8SVd"r~%(Qs ݊2]u޾]~=z *ɷ΃g+t~Of$e?J)/pNɁȚ+6*h(_$KSBhb aAmŤlpL+I2.9oȀd 8&/X}o {Õl$*JCMTwc <&t7_=#TϮ@ƒ!ThUiOF_1H.՘ %bVouC*AgußIS;F[N$l\+E!5yd~]"TIGi j(c|ʗw|i~'wZL5q0⚕}LŅrBxTߚ:s7xt" Yxp,A G@;%.lkהmŬ.+V+ ֥ ltEVB)ȤCx&Bܛm}CfFpneSVίJccfXdp ࡜{8SSccO0ևҠFkNɪwK+M-`Bn//sYʰTgMNL=` ‰ͽ\TT7.I%MBoR<ʼ-~8DDk02|7^0g0r UG&%)fjSo.6;-Rvsat|ū,8Yt$\vKqO[.}X*xZvpZ<~|~\yk֪"2O#,'+^#~˺&-q.-]GLAȷ ׷ԣ_n'4js]VxvȾ5GB\y};f;І;m2%H~ X6K=zuR2(v ʥ[|~EKZ,GKLLJ9./ EOᐝ[;[e!EH+$Rp1|W_s}M[JDgzF;k4 ;ekF:ҵVxGuUjIYݝEUS"}eU|~i8%̏1<+a QAwrc؟R ]b^V$<\qtC?;~'2a8w w!?y̔~?!}((Xo@ۢӤ UTuZ̦z8\]32?MBOh9(%G&yT!M7oQ*פBvim@E]N{j /9$/qe e䇒)Z*2yfH޹=jn},\\~h*S75XU"SBFcLO<H1>4`n<ϊcXĩvyqM6`$ :?#p)581]V>Z789Y+mYؒ/4 O>uy5Ӹ3jª5ŏ+f62N( o\;Z\V~Ex!kI˵z˛y۽F= JӿOjfv:F+n8k4IU/Ƶ=lKo0le2x3B-p0 <U^'Y"ݦDmP4gr1epˬC92}><%86 cU ߉8<nz l]%|h:*>hvٽ֚pǕ9xw_{DV% NWAI].Κo6[:v΂BȕӯŞn|$=iZQzѼ% WFDco pT˝N_ӓ6 >ec$*p7k;QYIpu?9+*AquQ"Q|QY u&m|d.!9\F2 ;ͪ"\w|n+wy*Y8]ZNh$O-Jq q;#NbM5K8.k oTuvt\l"|D'oNPΖxpS:uռ Yn|t55y1TFr'n}k~kY<YYPDžE g887k+NX$%3g#&⊲BpB}}OȹҰiȵ IwWlYc0V#(*A{Ur;%yds`f!A6cJRcj1mY.ɀb' IyU-O,P,6yY{QZxZֻ Eg#7i`p B̧" o2o\(ST2>xZjv");Ɨ4ṯVZH܁;-HG|oB";s2И*g֐lSev]2/!t΢씃D\Kfynij/w1$X^V!THq-z=KAp|k`{pgءŗm`:JdwCK#G =5oC!w/me6CֺLšZ5 .s?:O7tφU#z{ 'Bfx3-1,o+I\;iїr wM!UdQ<cןB-6Vo-5X0$,k`Dj,Ʈ6`aFٗ xEO&5]Z`{`^rm#\] ΄-OFN#N͹>mil@hnBLxyɜFNh㈗dYd+o˾MRR,ra5hiRȚ`g _7h4Z MkZIylcrqz@1Ɋ5rKpJSI4VӀ Fg yi J! ͙']OܬZL~(S#/2tϵ<[qgnk}a ?.b -+m=]i3G kY$qG<=H `4`/֛WP?4/h^j}+q,Z)44P?aT<a<91V#q"Due`y&o_8T1RY J&=D.{CV&roby4@@ xb.Ηli~r8=Zy_!"RVok͇xMnDd[ک^w[)85)gc+NR33"Kxƽ@cL$z]mHXC@ 丝T0U"m  GD­C^4iT#Gvǎy½GcІ^{ի6=pCØqQhũn n5sNnUQk\JpžKM0J3N_m%!x[a~O⡵?ֽb>qsvxû3UL|'J8i;3 t$9w N<ÒRs *uQN DT1޽jWR6M mmьH 5Or\OTy0 i|M85sɌ8RրOa(Agܧ܄1|:-{}&&m Scy QzkX۴W(nR i5WG` &;+=jSEСVd?)iY/^]NT"o 'Gi/2RzmeWM9k8tZ 4Ex4-)T;@෪ :X.!@dfETD*r+ * jwDZ]FD [;\&}ϥasiWT1ZB>\ ʔBy _+>j>sbܡ5 z;bd}_bs7amol(ӏ z]d=_F=6jdRm_5w邌bQhh X2msF-Hr"8|? _2M$.]U$hjV?'1|uBtKBKc T+?hU*BUfz`ϵ_ \א8R^ы+oJ-v]y;G`%-F[lm NE,{LQ ؼ92B㱨cĄD߄,49=[[sP^ibq0o hΑ:-~Վ<;slxYi ]~fː|\9l.쾊.3<#cqigs-)L1/poP 6QC4*(_Ԑ= ag~Sۨ )+="3U"2 o~tX06ެ76%aR7\j{ZyB9~LZ\HUL7^mz z o/Ђ_{AOV˔Ut4(5arTD-.G!g GsCl9gogNcIN;̎C=Dﻭ?GWqW qr03z]Oȸ : b֍x\ Ov5GA]e#]Y^AÓ MmY:PHfSE?].׹޵[!(rDJ`"Mр)76U v9o6O/Htb@kܰ ޘCJW`/Ty|=op]Zg 4GJ* 3@ߝllbѩWtUa j6$q-:^@Z.X׏GRs 3,m.vuoUf$ϖ5z: ^ z'za%zhW7uߍ0)˖ePo<6"ϥ3:C˼EWlb:yzCs :%Q>H>t-U]6#YyП6w~MJ!uw)bU7<*JkNa.\^3 1H!"WhkL;Yo\RZ9k`dcE ݸ'׈56ZCqHxvʚZ)nS@;%{^݃WДS߹ы&Rﻌl~jz24oefǖ TMS#܎B_BL^tCvŐ6OUq"srZ@kp s;|( _g,pXؖ?6x{NMG v1G,V`_SVF-+AvW_ݔMc s7bĹrSmw$'g lQ410ߏr/ە[ WΊs͡ix1n9H GZص?<=ttV݉R !"Uy׏ЀJaI5_&1U %#ELVjF%đVQ@;$/i6GZaoѩC"Qv aOq9m_b/IEE@>T,!ORN'DrqBDk a} nߎi: +nxAamq=р`NI:2zmV}~߾ˉB@E&MkԤlRU~"rnѬmRfgShbJ ~Qui7;`60Y{cCŜjfhQiu "U): wj%*t Ţo}:3#&t U.J](=iO_FUZY33[=]}MyU3aR?nr0 A$ B,b$%tP J#ƶ{eƇ+H-MW^L<. ym9 ] 6@'bB!1Y3:"&k_#@W~Nq A8G/{ן]N"Pr*-,nDX-N)<6-])nl{4zZ}?kp Wo;T45 n]U3bׄsrB/)`U?G =$ ?}r8~5|!T`$yp i{OL\9oP_t7Dq&#.=qS/Һɷ`DʙB\[7l([nhP/:ܣ\ڏ4,um{YѧA gj(B\qOU*E]u jt-7q!'#)9Fj/"9`]|g{Ss!kq}w0„`ϰSNX,"]JM  8yv7-"R水)pw1ϑ S}l]jo_(ҷ)-{A2`@~jf*MĪtx;ys& Pɚm+UCy`wZtZrT,WCPDC %Τca(wF@!CndD޴Z8z`MlOD( "crUH5%Sfڈ_4t70P<A{tXiT /6WuR4)0"ˆ}㸧oLHT@ϝh 8 ;^d*n@( 4 9y3d# jdGkߠ'cd^`|FIG gbDa+OQ}e˧c:= J0V$ hk؇#K[I.FCkWImDFtDŬ&EaVbP8ʎֱ#Wb xZAు2|4{k]t{|[`Nw5|,duy9,^#%_ &08NGA z3xIZerI]l뵒:c+:䇀S}!|9S{]@ nk6xG.VT 3Ei\ P.UagUAxǙ? ǀ4ȽN-'{C=MT}+[LAزK/"ZmG%>6 Ramno%6\4T%Ed%h 2#.kDG NӪU#نY_搣Ha&y Bu ]f,tr°R‚) Hc䐥P*Gu,2捒-t3{lk\QcHliFrp,שMAi+gU\h%kbLݦPfLn.ޔ8co)ه 4rn n$קT 8p*3 U{KpA/dyP$jGI#ތs*Nesu_%9/85O%Ih7~pt!gkk1Pta-U6Zz w3i=s`#=6$nG A6ICeMoG\_q)~Obnq~aQWGrD!SZfke: Xz#BL{7>YX7H2pZK$mXe4w-WʌXXNKO$$!X7C6O)dnp[2]=ܓ{caP. 3Ahma2Sk.{.cKqbkjX(i,= 6]Mp=+4?Qٟ8VP 3y(w,9%%xzŦ :f|Z|SZ䣔uGTx_ch$Lad 6:;[& I(  ԙ>Q >nIwFlkjLUvgAL})P.ћ4sEQ'+Y 3FNXy-gۆ|s]>l2VJp>  eA!珆iUG`^hgSAz[Nj`~%Nqf|B<#3mY! ,q>y F~2NPwk/3ZQj39(Tn/zkKd4&u9S6V< ΦYCq$w&/t _ݸ$7>2ڨP x/KS>π\[` c̔V+A>Me3Cn}ZZʰ2XHm!6ˠQ,^jQ|1,)RZNЂ'1 ΚL6sQ6)YنvĤf밊hƻ2u7++v~buEX"$tR'pXj >U:ͼ=m+"i?63LUCW,)"`maݳE[6E/XpiVî{HM=C:캘b[٪1*0`6!`~ܞj}<8#!<)_do5-tg) 1 |q"@ auokV#NHb?!gf;n-Knm#mͦbTB~q>>ϴALZ"b֗@od@ƭ+$]YQ&rsl ']xWVfM7WЫvrQ 4ޓsv\ Jx> 9,$MvW &xyA3uEoͩV!/ p,ڊ[I /kE̘^Oe˼9@ *ɫAlf4:"MhLewJHjΎg˟G4? Zlpf5gJD=2% ZlOHQPZ_X (Dj垁`#%Y4tkŒo']֭E*J0\IQ(XRQ0 nZTPBk qa=-~v  * MAy^ p_q(إ..9{abD5F sqf]KaL% =m94#798W~1ZsS;$D9XI) yȹlƿy r76vbq՛4Nhׂ?m+g K02RW3# %2`~pVuTnaRJ̊45W))uT~aA]kȘ;=(3YlȲU )wAyi) *ŅOL(>wZ,qT5&d!%5FY7RuQ: /r &Z ZV@RJ@R/rܼa*]7qXtF')nfy47U>Uà3|?" 3n}OOeC|AoaAU"QuK"uj8 ^Eۋx!sx@Ź^ʵٱ$;|pA| j }=h)m+̺Mnr^|O]I{9)A.3hά~3]oن+VDXAy>QS3GƯUfw/=X>4r>bs_R &]xNqIzL#[y1<%Rg Oh)rt>=2NMR@3;Ãڎ"*h!ji } .M]Tr~a uiL}|F2o0k MKrsKxV$=ŴXs:UsTDF'\~~W^b/-FT %L112Z[ 1IL4;g"Da%*==×ޚo$T;@Q)rNŸAgc^H-3H07AV<"zfQ69DI3>Vn:*{Ԍ:m2zJUk,q q?_@UsEJlIv CXZr0)e:o+& * Y[UYh^Hؚ-Ah) 8ݫT20TN}T Hi $HG_!U۷ ÑWY6̛[(dIi_B]~Fh]cHUtP[_܌|gj O{켥I>X5=f_>\I}j*|`Iq"hw^vvrXԙOhk>K7J1A92`KFgE^2) Hz IL~_tfYNS^6 0N,i_Jq=N_z ZKʏŨ"頦99E2qJ2ka5PN.nF.ȴHHN q KCm3>ׁ_RغS;e xMG Mڜiv7@v`jySϙL4\(>=H㳛f5ݕdւ4J=c3c!e!ekbL' J/Vݷpw$OU1(]AUFP?Kq𪑉Z`4vRBVXNU} +YA\(&lpnD hK+vzM˺ZWfD0XwaryсNC{\wPkML@/a*0Q=o)AP3 V*hĿ1qyZ7(%7ME=j\JaD3k8_?;,G\?řᱭh.%|AUs&; ,pYX\ЋwF쾱c.X̏ 2aZR+1{@D΀7[a< <{|`nik޴-W;y[ Y[MI<e/|@v=]p~O<"eq5u&(ClPbͱOL.QJuA КX`P_ن k*A)ȇ.`ei>@L40?4߽Sz:Hl.>,`=ntշe%Żoa&Z*HF>E-&|ikvG"a-OgC:97*U|Iۓt`1W1 W~ڐ 9oOJ@˻\.Epv#T8Pt}q"ǣ{9?#-d@N9gqO fdBC}j]OzRz{G݌]=@w޲G(qN%fSڒ_i269`*/<Ҹ^j30Wi*)fmztca-*23ihX)@~e t)K1-|7YsOnOu?!vv"KHk(Lp, nളN(vvxL9Qg/d@eB~ޠCu~bʺZy֨7+gx|:I:mfe L<wOho^X擹צN(_57یm+B P*y6λX /=KΦH~4r\TRmehvS *9i>J$Uyt^+sʎPXq Ajǿ@Fe<̈pX6S A*doVCjS)9-\ 8EglxcjfYuc4L0YI- Cc ]#o^:u _ <1v}ph\go3JmO \\QGhU. 9E:[ePש 1#f>u{ +nwy QNDS5͈H1iUY7(vz]K@P }6KL@m.E$ ْ|D;im x$V\u?BaYH?z0ڥ1¤Yf/a "#R?--QN.J=n8j_ edʡ#a@]I2zpto{:3+ ֢g X_'If"=ӌw-P_"'eRJYҏpNmMf7XGix 2i\RqI/"_^tmk?ϗO& `w[QvdƏʾ(5/C[Hӆ8W"'q.^i1XY(c c ] ֓.S ִ# !3 X JR|l0ʮ?&3geB$="oG39MEDnJΆ[\} կ a-ZܮBx%zxZX?ܐ*B瘏fu-Wz;Bs\{:Vyݳ;1FNhm|Ito^/’YRmv%G>ɼMgHǾYkT)K2r\N)BШFh F/&ݘձ~$lx}'epyGg٢;ɻM.Q"pƳ'!1ek.અĦ {ЏgdUA)Z%Gɗb8E~fm $BJїD6%oJ2& \픸?GَK^jmI.1^T6K7 N|[s6& ZJ}rBecnofj37 2쁶JOP F}C r淑( ΈdMo,ʴ-{E,yV)v]愄}}n(O0(gr2Fǎ4 ]F)ePҞ,RA " vI,#7Y6u^$9!컼/ϤLc}"S(NdӗN˱U˛^SxJ5y~g HtFaB w{ ~ȹiVoM5>pׄ3|0LnyuĂhA/$NmQ_[".@jcni5s"\h&7{h+n8n< %6?Ttt]ԋS/8Ww>2]H yf=5]ӿْafx^ \0|Q= B `'Q2S\?IN  |3#*Mrk:>o)yqqȰ=K?Hǝ9CJ(t2D݊V;XyQ@w3%;Ql7F3HBi|hI O*&MJv4z2ۛS(<X/=|FYtEOZws `raIO8Ty6k66њ ©oڇ ^V"V޷~28ved;0}Aq8bW,55[XF:2ܱIQ%?2 ѠTB 2Z Q+`NM i<-Z F1Yuf(8_uR;"Jŏ"wIئJʲ e1(oőOAa5*3hM}!Zea'Ҹ } V6O@0.F|XC>ۑ#~G%|nwZ'k+΂,(kN;d8)S?XbB7my񉂚+rU2SrV5raxg#Z;)bܪ{tg|ĈPD1%q4,eȾ*3ߐQˑ~g,$y76Nhyo{ El,'·.XWN!h y[\1RsعL2~N[g)ݰ*@OWL*z WLeln@(_3'}]tmDbe'$ xyuuoi2{z"WjMB~o8q&l^ ]URtN=3yW&/+I%btDFq̕yzIo 9Plq` 4z{ePF72λmiTE*-|;(Q)}$_U)Wd_断-?%oR ܴP7VALƣ[C^f맏0a{K0bP 9QQ!~O1?PJ {ؓ$ rcd@qG)`}V},j^0GL gȅ׋k eu7L~2RA~* @&8ZN ';A%\_Ԗ`CB63QWelwm98A6qJ);4LQ-bm'L/lFvP#Sw?i:*pHo"tBF%W+$'$q]֜uw1ciɔAJпL{1?Ho1eONapgDyF6? CFJl-W8Cő8^.s $%B*|H"askm=6~^P[w];I#V}pdUhNͰȕKT~8 OCtM"QEFx#P^[gu4/@})9T=|sy7Vn9ѣ>s\8;P|`qPAh+w1&rq.0~sH]i7ԞgW.sѧk%*4C@T“5qg6f8x 0roiQ#Jۡv j|o>) X/!e+|o%)4 5=@ v30OO¬oVq>֑\s79ፅ {Bߨ`X=4e)] ׹tUvT;eDu u(:_ paӵ~ݡq7 %ϠIkk(-nx`X)ևQD+PB`PUմ{ T.U`P*m2X9)X0zΰRNiئ\MUѯ-hA-.Ů>ˇ ti]nuh4;Q,poy)CA]s&j},Y1zPep4ykӹawb}JZk kJw2$o4(zo KOj'D3Ϡ[ P~E,$'":F@OՏ=S6j"hl1wuqo+-= RR.7[3㪁۷r.U-X%W%d—~3CۊrRm%-wl˗Juh,4wۗ|ا;<$! "} 4*yF8ή*"jA=nslޠ1K/,R@ A][T`SK=ꀦI-Ҽol]'ϕ4Qp6t!?$d<dBV 8C҇hhb!4 JP $ B ̧edˋt'GGk7uMe&b~f$2iE]^䌶}r&FQ^XBCnV@s_ $uX"Z9a`~Y}\ Vv]©Jrd'7; 1 Du3#޹.FX nD3gМM[)$!9)iE&1%Q`a<+xnN. 1!Lޣf0^O3]6e J.;&Hq(Ѫ v1|H=/=; (m tm`[/rTZZ6ݝOYnq ii_rt7#^6t9pCia< >SN|R|)%pk7cI,2r\${kyC72vvчkcHn*hØwixI+0`aoeoԬ؏ٺЙ]Kqs$p'3ߴۊ7zH@voaUIoR+z ZD<=:2K(NJ4t&{ךfE0IG9 [5bo/|b*^حHbz+z)VkƺBWNX]%8962*Eؔ7ID!7]>Ᏺ^I &+ZnmM9ki,%=###6?7(3vj Y,oZw՜j$!Q1C)F}١ɍBvXx)6 ( _Z`6.^ nO+rZ.[՗%:>[ r*cX`͓ǵ1u?Cmpw4P)e2] e5@Xc8YN(NNQ∤`ѪhVs'Rem9n++,u#^[S6{ltMec]ۃu/-$8rA#`~8{֨[c0j0z OmL$9OmtfP@碰@'z5c4Qͽ%7 49ʈv# ߠӧSfw.-`".WkѩĪ@Ҙ4RӢQE>Vb&e'gAYAq)!4]XU ߵI;ز UPHVk"2I' "<4~& LZc" 1BݯBh{ c˔9E$7.憃L<˾eƄ3H/-`3Wxޔ;*AcA+;f{@5!;l:jM ܊8wT9rj3WwMlܘ1m A<â[͜E(Lda%b6?j_8䠦ݫ#doK'E4@OaB{.1- AF~>(4[w60܌86ဟqaJa/*1C%dYjxr8<@ftq-!?mZ*MMQM"0jZ޹3ؒXF}!3`%}+혯R-O'j'rb ?ExTPclH! q!8X5w8LdT΢0p4%lbaKX›6)$o QH~'MÎnR!#b@3n#=-Q|7RS}r1eyPx0( = Crp5`=IǹdJӚdVR[y'DXIw>g# Vc@! n-ˮRyuԢ_.۵h{jvf>[&>hOqL[ =A-H+,"=a׷vHZ].o<ļz &f"<s?JA+Cjӛ>:>mq1]?Ȁ\E<J_'8i?UyXĸ!՜(dԯ'QmNNpW3̠1 (u ,qNby0 Ar 0ͻ3pI iYPJ=~rmjfU:uv1YN\iOFtGgxq{ʼ䙶iAޚ9G.;qHJ't9߬70xI9Β= 6'sįI*A-֋|*2Z-#'e Y}M.u"0ݔ XꑴeSRnzA s||Ļu@fx;r733Vl+ 3do-$~A+ hz;1Y@peru.CETk2IK;ёJWDv{~keV2-O8=|Rm>k*N-y4AY2J☳3h䥐¶Sn=~浔>> QB$VM9;<*q nmi'*`,q-R% ,@)[i F97fM0d|ˀPF$O_:1-]#%@Ba km8kN]h=:a \ï~ MRZD5JgnrY9G">/)8l W{E& )Y+0ayR.oP;I>U;wlT?{Lyx*on+G,tX虢Ri77> /d1s57=V+w г-jTypT, BƓʡGV> J5f |[GV{> Ս uN*c%AZUH y2@jյ9?t8G",M[00%Mw)lz]c&rhtؗ\٨bKRC H^O{ *e&H qqWtawNIr$kG!۵BprAjl@9<ʦ&DVOVJtxnÌiQ\jGB|5UJL^to\KpU[r̮OP% w ې0EEV?Armӽ\NE9y5[IDeV__BDrs DlAH2*8>h<@Hop;\ZSb'|Y۱;C]]xO6=PK(SZ\QbO9Jע": L"ӁMN$'?EYqԿ,GG"z䗍M>Uɨ-pt|TNDr`bSoO5qU;PLoB.EWֽe݋MiF~0VML`L&kԪwB{ް!M[^V_-LT蓃[@G4u=dn< 8d4k{1CЭQ sYE]* TKwȋ(c PōFhΓ{ʵAMu_l4-362n;Σ2>vJPq0tOa$ WSY '7Q 8NYiWy1'qmi CJxeo [朏[,iBБ #`A7Þ8OPʌ f2ܸsX^˴1bw 9ggI!+/Ǣ-dhR`&f >U,P7蓑Zq7:o`]+Q&T0eER}!UPȗvmWB լxGՈk}yf3G0BeRkBJ!^ᙼn! -L]+| JG|&;\k"ѓlN72gX!.H FYr⟵ HZ֍Ex 3ӏzO#b@@]?~0z|k,b7(uԁwŸI.MC;Wb(qs˜9 z(pܮ#oEеǘŽc42}w=C+{[l<Ɗ3K:m,wClr:g[w;uDEt1g3qn+ 5(.ꏶL7޵XK-q!i NRRBOH{m}DاeZPM(0SjB_bJQ /O~ ,XlBmS+-u0P@Mt=?g"O=ĉ].ӅQR7:Z"k މ>O%sM!ہ:Yn!. 0 J9t6lە7g5"yIO8ߵm_̪/xyADR=u"9HV]iͰF*o(v7`x_57[ }ܑ!2{H%gyҦ75QjE1lC2X [XDetѻ+ΫZ7k+i65"<3f#h`x)$@ѕ6*n~Z|} /`y rS;d/nxx@UxH)ڍڵn!#.m\WI23p,X$w7kN Cp# KPYk[SQ/f6<3`/gMC*|/ۻW2#(cpz@ty8VQ1K C4A$ӱ)vAzОɡȭfu_H}]Q>iXMUa͏zL6Gdqc94礆9^kLɀl4@F,"#]׉Ͽe W;X![QE3ZkAV+9Tɲ56.[4V|²06Ǖotn0E_oYdc Qn25'ׂm[p}LvvJp7TOv̜jwI;C F$8z5rI{0bE c*RO|E^cbg ]c\hΑG dR󱮃9-k;;ÚK[ o_Ci+H%|YQQ)d }~ ;,>lurCpl'qt5ŁJPFX;faGz-<_ V|%Lt?)q^Y)5kvqѩLiP)W\ fP"(nd6QTk;xɂפF([L 0%y^mˇ uC}4osI#pϙDt[wE̳; ̠ >8) r:&+oea,٧ 7n%әdgMycta,; Sj~Kj)ooUGP!,WDXP>9.3tXdLH2gb*GzSF VChC>" # +Ÿ/HLmJ%W.RҍrR.QYš%0vK\: ƐL~YCû^u;ayFmXƒމYg*[zLʱ`-28&KbĜm> %'!Nybwz JIO|C{]rY[|7i.3|- ?񤬭c`%ljJ)[ϬkWO Jሞ(29c#ݎgIV|S؊ELI|g^So'r.ۋ%D${U-B7#=Цga 3/Koe<$O#zTJ)IN̳DF{uakr{]K"0mHF#v1jܙd|;E*P%)NِoMRʏ%} 1 ]b|-(b_vʓgrQ5ÈU.z^2+/]q?UtT_.4ϝId.ehqU.QMfɛv}!Ҝ q6S;YXtiDy Nv0%i}WC5™Ȼ?Mu2|˻5tiWļ$裗, o&7mLӛ2޿-F9 )oi1$#ϜXucceӣE6|V:#Y `h^#g(L/EOx 3UdsM 4ňPX*< r 0%&@2Hp)J7sG>~ pJ <#~w|ڮkˢO= LPRB}b7AE}`߮%ur9Z46Gzzс&{ϫ<$g mӫ=?εxƿC7 {N{(p+LRx$4BYfG%nLZC0TUGqڢMn;O?Z|؍#Kj, v%jJ_tD)3ڵ7#~ ycx> w$N%6.F(*CV7Y ޶`d0q7'8^*q"+74ŒlC3{v9PvR\s H!cA|OD],D/c.\qjBs-SM;k#ѺCO+,NÈv7D Bw t[{ȭ=^`S$q8@? $0=u6n!xq*tMhjy:3ecŶ 4VrjiI횷G`Հ+BPAuU ׽ z7<(z;lN?O}S`°^:j^OqϑU 318MWb* 誙5ܹjݳjbO[ W/S@uy;$Rԓ_ɾ ձO#Ay׫ca ᦃ? d96'H@$BDzYH'3IkxϓuI?܌b|ހݠ4v ,ZǨȤ + 3@K!m}b^Ҳ5ᖾҮL>LŔDXi6"BcPgϥRUw| <з489wxL}|I۔Zڀj!]\9u{/9e%2bh*PqL{ot#[W:b_CHxg7#io38kekB4ֿS>ң1J7ZmZ X ]ݤYEB1b7,hlHFw_=]ɭ A E? &4s>@y\0Rf./FY@hy.Wpƍ n G86.R}q:i Ȥ'3eSW!ߙ>fuc}Ӑ`ÆwE뫠+#1J-F\3as.:W Q7;< !,v< /&LN\MDEب[٢i])h.BVY= >k`Og^,>̲ݥ <s?X4ɃAoT_4QP@mR<$򯱕*OuQXȾ0sL}Z ;[@'U> 㓸yI"SiIB ;I0ȫoį\H (3SK'k!&z&fƹdžUHK7CyGƙ<\_+-/C9H'8"_uw-ojv"eV>OnS7J _UbEܯIN8a2P*Y&[0d̘a(A^I$;:erU-Bs06ur!x6Fq FkgɌ3fM=QHyf{fu͛i}L*֥FGhqu.u;?!V|I<)+; ð{;j*͢A&4Ruhh''$,Li̞[p #W,ƴdQYqhwNMd  O'?q8gR0Dry (rl_DwSJl$*.oV1"yuYH@5 fFnޒ# HG! . MC^f"lz#0fߍ(qq?7I,R'h$t]wČ&DaSM%ʈt6I@);uzx?UD:n@rEHu3+`Mr;b74;FUG9>w5aLDLR@㪖j_XJEk dFisFFjqDblzrUiJ!$RnTηtUB$@`Z|s(Wo,ܰo$fпҮW"`\qL!.'x~摨W* ײ(Ƹ>q0W!:`C<,+򚟰:0 `dنq__Œ|~\ne$V%h<4yPN4:W$Hq؏enDs Y35,U!cR1/?DpTZ33ȉw_(`] })LOAF{WzDUȝ@m%6rf$(|#sP7qD-?G ε50%Rɗ 2 *(kT?@Q"S\aկSGi)Pab \z{8 %ȩ#Kp`n,No_\V<&put~ A%J{?tk2=i8?ZÚ%_Fbo:c*[QUMi@[gQv!9rNĝZ6^7r6H1wY4>)'*m &2֥4hCc"aBچA t=݀Lwg>. 8KxLPY:VnWrN@E%Y)O}G~VQZlq=q D|5!-J *>#V1}?zw/%S^"ܠ ԰Zz7eP2);k1Tޢ~z+XC,0o)`g'q_k_xs!{i@3\~/ Xkg|^^m7!pb8JnA.t6,WĊD1Nn !ʙj#':kZzo iẋ[|SV7WuuC@-[EܯXtVC+haK,}|yZL:R_HI.CГ?pcô>&A% q5-2Pt#Ϲ;$ A)ONz`=c$yH ]CnR~4YP=3*7BE°c:7]m*,T2Z)*1A6pE.*mB@84:IA=fX1ixC}]YN}6m!dk]FXoޜ # WX0tl썠dߚQ ȏjic` W(uRCiŪn^WBfڮJ_i%Wv:Qf/4$[qr2$QMF~!_nh7G߶"tw'lFS`J5G29@t5ի)&MB;`M0v:0ȥ 3ȥL V)/QCD[y33)ܢoUǚB 7ΐgY^. #BE|t^ɨXS~0C./Wֳ%!D-@=GJYμp-s*:Go4C0 BxTܔ>ۏZyw WEݱNWbj& |n/cs,vq>;ᗿcj%0aۑ/KA%ĺ__x=1M: "D)٨n.X|r2Jc݇iC3#gly0G艜mg֥e *)b򝛲v0I;m]mQlࢤBP<%t`pIy6zrnapJv)EC`duʞzKVt*XKiM]}[943%ʧ}Z80Av@xCYsf8 C;Da177Sl\8Dohj߽'|^$E >Qn|> 'uc9j'ǣC>bo:%@}yM'> /-_-z@ tvKаӠG <5!b+1׍|q<9s0, &` .)|(\#ʭ-@!p>HyюhHx:fq+ biI-GLJ3P$Լ/a[bM]nrWnL#";t XXXœsiM]D2C7_AmNwj׫y1+RLԄ*&Yػ!6FGASUve.NZ eJ[6kwϮ#iJqsNO`U+ ,戬gE8pI םƚQA- 1HMcl<$ަiwxCs$Vv*}ض/d @П[)#LΤk_nJݨ3{Uڛ.9^(ÆYZxYP"37ž=W>(KJq,ܳnj͗cTľAJJ e"g;g[k57Kg)Jš N܆ޫVMt#'`~(9է8o44A6a:oRI%-cKU"[а'bj|*S\Bo=bL 4_}PE*Z⪙ρ(bI!E9k:}|>dcrV> Qvŝ+}`uk{:,4\dRN*S!Ib4Z{E+d?{%IO;X<t„x_:W3 綤6C`ckk+ " D_A#:~%ۈFbwwh=,J25l|@hԾajJ2Bؐ'>ZPQt;uZh$zpަe uQ3GRC2Ye3QFJ?'p~r3/jjRSԡr,/aӡ/(g"9|ppyݟaq@߭ =k5Qkƒ e|GЉ |Є|i)R#@OS+ zcdc~wC`v>mrWjT[6(3Pe9ip%Y ɧʘ19g?h{z*4^ܢyGK)@p&iݣ鱲Q 3M"UY߂XYGj772cj)cQ/~)g mTz"#Vϒ9 oYVU#w±b۵J4d q?g1UQ{[9Γo 7|BH FQet}>5R%yU>mYr(j4z;/B}p7Xjkf1Ii8H<6z3/Ѕ'%Ѓ /0/Vqʑ/)E4`= +2љJCjH<1.g RPWQj AnC Z+S5Lθx髵BH|UӰnQy$ BnVQvg ɊUѡ$k(Njf[ wj}nYvҶae~.W5&:|u=$ Ჹޗު,efv >p} xP)-ny˫;o7DU01z2#6Hu9H!,Ά+l3-C|B2$DL٬MbDGlUGdnַ/%ܿAջW!{9fcS(${˖L(!-l/{NvLnLUd)PgQbO~xWA@_xy{uΆ7EG$I}kk:Y,D8C=@*^Z٩Z"Hmq@8sd{!0P$ŠrG;#h RxR$M0OdF3QhH 3 CZ8 +K?`Q-9V@,PӘ_4NL/Ή'A\-<=32P-@ӕ `p3S+ }\k~Rb MUFߊ!'B8̮ut>/ޣݫ(T"'[ȫfMI:qGi:ए0?ƜLs.߅$HSKy)UaK5F,*;r[j_U:ѓLtVG/ e ~e4OQ0sZ{χ­f ѽ(,iIq=(K034_Rv ߅uv|l=U5ԙ쌡*kbl Q!D<е1^쌾Zܗ̥6= <'ƚP!*m{SQ2Lcӥʐav,zkB]kw2¶wybpDQA 29וe~^=y03>b5IK! ) f94U?+ٳ`WEd̏G4SIdI="dW[hNF-zPTS4חǙ9mR`I ])LK&FvCva"E*طNc$}* B$Nߋ1}x roj,[o҅6fNng ȇe+ /{Njh yP` 2G})Q:1,WD~}=[2ݕ'Kb|M> < e7mP* 0̿x? `ꉞg*0R OjSv|T}0`}Fyr=829M{JQ f}ջW: a Z&VhC~۸Tx>"è7Hꀿ ˂H=x\~OBn'XnJ2R'0gmn_A&9r Sjo6', ڡgUA7af׌{=uN)OEU$XLh ݝp@tڌ6Ӆ߶z <{f;#H~M;A:tMnc3GM.a"='r'(j7͋pA ZqmVLL8% JSSm<& ov)SݹAEw[ЂH별N￳ VlS6%(b5vr=9Gr^$l e-e&E'ZygdD"?H6L-0\6+L5wn4@k2ʔ6o!A ] \rlںlc%MyY4.~Gtxmy7n?NS&8?­^*ٖC`pاScvkJ}8XTTo-/>;X0d$92f#T+yoA!Jbu!*=V߈h1ww,C RTpfn=.Dqg=A2RkseO&.s ZwG5GAuP`/5A_ز z39Cj ,Ԗ;ewӪkZɗG&M}ƒ9Q6ĐGe̺0YCzЋ;]@` x' yN@#dyG-bRbޛi zt('CFE$r (8~IkTݟԢ_ݜC|B \Yቼd~v o^4BW{%H,5j_O11fP" scC0 jm >Ɣ1\LRͤAa{˦ax1b'nҎWq [ #,k X` ĸ 1^v'$8Ywd}|c3{Gj^XxܽZ^0xs|}J؊LE&}1tPD>Fcx.[36WzP)jy"ӂ፡X(PHR;z rΝ65X'alSMS;ᠷ6 ;tҼ2`7sg(дHO7L#|ޒҼP8C-M#5<)xn-]-47.ӽOg a:8_g*u1sʋb=sjs*{y=L|ׯI Uej>ro_pyjch-ƞY]PXnWWW1@jO9tBЃ Z4)'?1<8PpUBaϞ_ #0lL؊oT5a *Zaz_QDM~-{^l[[Jr 8"+L߀7MiuͅCNꑼ_ȳ̟}?/+'}إɖ)/c @ğWĞΓ織c:BITRus%8mnWL+>a1R茋^kښjj  wi^x.7@cL- 7 C>/ß?҇3'DsIu5.Fq czMo(iR *~(&DPmǢ 9e>79w& XhW /l<2?7-әkS1J K9{j~=hXmH)( Iܷ VAMi# F`,AV:Eqh;ۣ %*׿KihAMBJ:s\,R`(*p'hLIaӖjΗ:h=~t*K HSrcHW(IHI++""s`ҋ'[ldR8:~@vt| h .ݙu`)-=YG"4$5 ,Q,߇ k8{Y,'F(;垬:x,{W[$eOTN%ơ;;_RVHůьɭ%cT5{E>007k_u_;@ʦ[uˌY/!rI "Vdqd@8:N揇L n$~') +"6"T[x˧æ9#߫chQ.KGܓ1o+:LRj1ީSbٷnZo"Tm6A w t[n&pU|.<&=3vDSr;wJMTt$ᢴy |S`{kJFZ~P2c"֌9GQ?p9WiM^Y =3^PfLs'Mf[,E x0g[<#Bbr\X64!B8 NZGҫɿ5B) Λ 6(%M X$zEr~(7 e!yI)'q#ԥEHP⵳Ev?g,ݜp+7EZH+U$L%YdF$0a%\_|bT@hN]J5h=?xuXޟBk/T7+3HΛwS٠|5=s [䙫H/O@֫~lG'"_ 勰oa$}׵ lNOw!$%rIW﬋ڵ9ٵQL;GT]?,|gtY2әP^*)Alt{Jl#9<;uIF.hZD4EŮ]yԄ2^0[;|MEQS)xhTWܒA̯pPWbJ ZS?UqXKG%,= ꀥ`2YgpStYV G.Tȃ,>ZX2%L%9oNvV3ABxbF%[[7̇v7;EC9LU< "X-PƎ@*N[@}D-`(.G]$xjnB?|4'^:o!J轇L̐ѿQ&zމb)5%Y}}TW)"r;V-t,tu#\V~S^ T[:4dpv9:? ( FN lDQ-`5d(& /®@D)s1A}J z /g5i`XB!LG.HW-o 2Ǿ5 ED1a0h12~<\vKq4ƀ2UH* YMv뎹AQIy,mrh2nbςCxlP<*3fN+hqj}0|6&X.%r6YIN2(ﯶ9|>BS^;vrPp&s&~8b6F~]u7a>c*,&%xeAs}DӇD{l 0 7U"y:zS ~‰XT2(. `Oo֤u72^m}d5Òp#Ia;BqI(R!&&eԼWub &?s!rNaDԉ;/<}4{Iy9iHR0?t)YԃL ^dj+̍ljKRAenKS!xh{,dM7%?̎’_X^xKayN&3(;y+FpHP)AI_I%fA"|a'"`aO,Bd#vڽwc&z%ٿsHTgC5rg`N3ޣ iקVɳGٝ9ݱ): [p+V!ٖaQ8nӮbnHA};3`+Lu\:##3Yad;q7%9$ƫa/{ 4CAX8U>kz;so:&f 7.~}1RPyDxѓmv,9ApE:ά嘤K:1=`,$2]̞,w ޲u+Q k0pUO/@o(ؤf.dؿ H QEy=U6OTa+e{*_^M$?"S><[iMkttu[1ю{۫Xmmql'j+2\rR/ aJچu["1jB5G&RHIU2o/G&*NI2-CG\/5Oapp!D;k0GZk7Y~@}gH\۫4AV"HBwH06ܓ OՙGJG8~bwǟؚ bQOBV>݈=̜r~2Hhf<vl=GouI)iW`&1*zuD )AĞH/xdGQwh" oS 1XDee4#{B<IbXxˮt*\[)I]j77N̶a$THJ$ ,)#7 8ť',} 9qgO| :ܜ>"Qe+ tN SKshl,.UqEyஈ`EL+S?eےMf b }ZxCN ea}p7L=&5zAK=u2.[2*2j#6?3ic/eT{/Kj-aGjD 4?Fֆ2kkZom+(' ` , vuœ ͨp#'J|#̗L]Tx hullƠ gq*2;5 <nH6{SOfoWȠe~o/r3nKJK:EBRX!L4=k;>b_Tu:~gEPǰoÂ8 ĮNmciLbOGϦ7/ Sx2\DmfEuo0nuXP o_t-3q0.x7߂@A86zTE3WFYT>Q4@˻l H<Ӫ)3n FxHd9r ' yOط|+MNDŽ`_!仭wfо*rs0wԚQ=q lo4c"F?!)ӑ8D p\ ֜[mMG4O>GR4hy7*WR*53X>6хv ,"F0!Ʒ_T6x=e#c OX3`тG;!Vj؃t| PX7;!!^TjؼYeT.L^ \jם/~;!3ĭ)B0 }:Z=gt(X|o˝H Yi-1.B֜*?j$@[H*A U|>' %HKVF˼nUnNުO7~;h H!ርNSϰ_?Trx,ח# "ag7j+] >I>!EQzr+k2ķ4^w}6X+LHP@l@lNycxBa/ SHN/-ԘCf.]4~[ziHlTN(*k+Q56N ^8TD "#;m@7qo_ȓWglUb1ES_OnL"XS!ZfbW T|^l8ВdN=_˰>PQ!g:h(t3:<\ h c]{e~HIZ%!D:K~^ar9.gY$pyAFC|١NPBs4WR~SNׁtٯ-Ap@X L! |f[cIJjky$xS*.6BK51n*4wPI}?dB|O?'80Ƶ|bY]Cd,٩m,UEaG4ٍ׵45."2(M'c8!?EE|kiD ' Q1E FxaAli/3mnںZsr)Ra iу퟿W4Tc*:ʂwA.~1%"'V C9)+ug:K,m@ I60Vzْ:'#V\ K8[Qe &cD/vjK')7 5F@$#* EL&hY BB^X'W(LED>^ 5kvae5 dc97޿>P,9OiJ I> |B FH5ݼ 伜16=:w4h^*R /_GU9W{Qk |yJ6;' ,LYPc;\-&]N! }fӡ$_EaO1Br`KNx٠]!x93_ouwnYU0Seܼ zE |%y?0G㢕u~zTb͂\k(1(`>F՛&m%pgen>_2vvҮ#Ehy!ղ]}x10&ZR!Cs@ V|i ?A$Djh?O_c:#uL0w&D}\~TwD+`J'ڒJx nILyḞbT"}u:'JOzwKDx?&T6>l:& .x_z= ھhV^怒2VEؿ';SLLױ̔roC 6 Tn9,VSVQc0s^WDvőPQ#՗ai1*8/v  )G!&QD{p[$z[mO-ᝠ˔d8" t]퇲kjzG|:Pr0J+A$v(Tf8t~J=#_IwQ~[ XZR.oҋ͹(ŗN%Ւ9Tp {n,۠ja@Aƣw+a n=3ʖSK9mȤ&W2٩dl)C`"-qdρQXOa 7>?»սw.}k%q3iעZ6Wu݀]m([k ~DPc={Ղ3% -\8enZPm,u0,5nFF{DZdvq{O?KhiwnFDxb0zI?.)j"`QwzHL!vKGZxF~pb_l:y}$;PWڵ/͈;z4v~/jm%RU{mo=+l\Q'1ظO"OS6&nJBuwPi0gd'FerD^5~77]/i a$a*̛P0#j'n?Cp+YY!oPW77Y/nn8kvwLLj.*n&{*4ЬC  VfWX2`փQD}gfhA-!uN̒,Hуx]}m$E!awA`n)6Wm-<7D`?GBˁpta"/ʔ9AQA*Bw@-5C{P(ԠՖX%^6]kl$P՝d-LW[ }*rˋXS89;D(-dn[[/ o'åM)7S%Xv׼^<>uD!54iRiT#$EuvIY} /U!A[bb.ウh rl{S' 4@Ga٘7-7kERڹ%1 Й,_8uS#9XȃR_2-sNSð >hXJ%w>8ܳHD˿0ktx ڳ.dKX SDo_Ic@af/(-+Be\hǏMN~%n1S@\NpofH1Gn@}:UUQt{m< .S쁟!#=w(۲kC\z)^ܶe&\$ojf2NYV2@hd<p/̪]C2ޓU'0MЉE8 [q:i5оX-b?q,j^ND0,!scVT8Mƒ2od#TeTY(e(qܼ]8n?&.gjv%0ռF@CX΃7鎑r-$pJ2SIhk @5XEٶj(2L ]K"h0>c*_iis6_c0 v_"jrq\".֟'ֽA:CWQ^i\ bfcacjXU>^)M*UFhEVqmDQJ蕧xX vɡCx SyxpuWP@2k }^ #x HE 2 evcp`5Kq:L{WXBZp^ayv; NB]ټmF=yF܋m֓WDit^}&]3uQ'} sRmazDz7 s]*)MM{H@#@JZq,?Ob5߶0KJTJuMv3 B Jp߲4vSbc vA{,C],sRDH)XQ&?pJZ̘9X/b4^h0Ps ^BQ5ow (4!T'OY6Y#@T(Ie @D1mZEl"$yr x@JI;Fy /+‡ ڄc6~:q,jyLZu'7}I;S[ 6GϪ#?",2KӰ:XLU4Ia\9en0oU*G`ZlO+3P_W6v(<XEjhJ܇ڔRsp$ )@\ +%!L%z- `%bqLgX:!<դӲ;  *bL&SG&Okԩi_^HwN"зD&.z+W;ZMЬ q(&~/!1LFFFfco_ ٺq~ctB(@BZ^7@IDWVIҨ9NZ kIK?J6|Cf NbQAQ|6#@<=U^=JodXe-G9V9C؉(|{9\e G촠r*-8/q*xj uZodofr [ '4t>T-!:J*({I%o:(5K'չX <N1a|nK+t*Maj"#B׍: GcUwTRw"j:a[In,%)W1KS\`[ x .]e40翲~q]Ȼ>|j}bRQN[gIr"XA(Q9/`S඘e28EDj&~)Kd}w, /T4,p)bZ~ ,Ճu;`s?vh.$U>#I m,2gh1,sWcB8.UOLN[W !"Dř걍GtdM.6ς8r&2yyFW'sC k zO F L<[Ml)0 ,bk~nB6BT5ĩ0d}S 8wo ɓwKK3^epJ)7Ą8T0:_g E_~&THM(n4j93A(ߵNI!]} dL8kߙ8AR@|.#21=y75wҡzhE:afvFBna}vކ / !{zcۜB{|-ϛܴFJ&@A4\%Z%m!#h&&Ao/ Y[--Hu%p΄h!{h*/1Je>Jی 5 *@ݮ|}z!/D~pFhĨ搳3*Ƞ8ɭ]ÉP5BRҺ eN| ;yWybV{y O@8,nj_nnlgnNje;UIi{c18+`J6rj|BƒO'PQ_݊w>xKX(S>r:>?``t …T_y OIx0-3D6אaVЎGd$1 gEUKbie(D>)a Cъ QylѶn|jzcGP{b^Uƭ?l1i˻ 9UqO]:]ТjW/5"boiH!w\-AK:t|tg|@}Bsl-#kC唸m3o .E7 bT%4b!$Y:ogP텘P6iTn58'G=}ShfխEoP")wPho%0!>0Q_W*9ϊ%̰/U tRCիi4@DvhK76J!u\}9Όr:)Loa%TogODj(ܢCnAW?_D^=vuYɾƋ|_=Y!&9/F!c o@ \jP3} ػ$;f~n˧9Xm}72 L OI?21dCu4֏ʃ8SR@DQ82GX5>c%gttwa~b-f!i,o-.rH-rHW_ <"U}Z{JtvMd xd1uT=+iAb]$O֥T\ ӦP'vx7"3>o$˽5L-C:?=PgY}đ6ROƊ/WByٶ(GwEnSxTnLϛecoN;#)sa17vsWH""¿b0?r6$~Af"pa1޲O0'sX>O nҐ@T,SR]AUϯT]*]Wȗ; IGI+&d?qS#P?bGm-p0\u/(|0mN:3I"^ 84D_Z/r݂oCR!v8p6(,.oZ s;Gq2' -t*,}1ϺoVo~>>[5RY"IbY.Ve ^T2L#eKdŰX1ȲeNSrlָW}:e Db> %/sJ.3vĠTu* b;V:徝9&>5 Vݒ)1xgTXh?Tg`jv[9Z؞s+c֛; &[ҕHh`ۜ<"~U^P:?h3B~l%Ā,Ǡ- ԇ}MIc 1,ȡ#FF@3;ZNX,V_M4S£saV|dZ`s&>1EÈur5 p\2DsE?qِ=g$/& - Qb|63Oi.yz$qgŅQ )E؟zIqq=|=Ԡ>?..AwωHp\ܣ˸>qeEIgspdvz̜þBp]hn%f7wd;rHкF#ӘHu_,wkm9ǟ He7;k\r*;yX#feLe*+RT~^#.1[CR>g_ZӺ,ۅ۸Ρv)klbr\D\g .\5pɐY/OplwVjI1 J ߮< x`wI1`{rl[\̐5 0"6\L@@0˭J$&"m %|}83-؋Iwea M V #=$7Wh$Ebqؤ'> |ƒ!M\Gp!MoL!3%#;L|=ngvr7 /iSzԋ$!ru0V2|N0cf!W8\f9ؖT%_#S?H:gQom@4R@ܠ5>LgSoAΰ ԫMPE%ZL E;eA}EB2@N#NJaSW{vNv[ l%35mHBsKhyre >GŜN\ǞO wiF7 R}x[Q;r4`B}h֍+b hpĶVF>W&R*Rzsz*fR[?gǺ^읷o0 lND? TI6[TW2[AG9:I"[s*iEn)\}CXAyhXK^ɜpbm:$3]("'OXI~̻ͦ#p|3jZXltiSp jhO-ː+6C*;YC^X^'3g=;ˤ 8i$YK赧>zo^;2aPt_f<؃?3D\~7]"e;451d8FOrVqƭcdϓ֝jS4k?5؏ǜ@A+4zcV%pa@In]Jo2;ls"(Li1$fL(I!˃* haĿzԃW 5lbY"+"̏H~oZrEe6ظJ=) U.9(1C?2b۞ _Aȫ[+Sfg9 qE;8G25r,iM4DP1ŗ)8l_w#~ډ2)xW:C'v0:&1SfLIKAB}2+]Gݚ%DV9wPFTfz5aZJT:o MYU0e6iiſ|JxͧtspM?R:XcτT^^ QEߎ{`Pl|*2'~VRUgvRlݥ5Q563XJX0,1>׊7oXUX4pвbܶW/Prig;bwmT7 '[F,J< hթY!VɆZi:r2ŀcO2t,-~w[mĝ)77.cT2EqΪe-UM4#ŚëmnU^Qs-Q ;Xv#N%zÈ0* 9CzU@/Q?T~d.$/ 3tT+V펚>ft`R#†p pL1ݚF,> V7(Ь*8Eo{Z[[H| =-+D\Pd!Z/^& 4M$;wKҿoXݮ *#y~kRtJbp+^kuLI:е ^G#o^U[ix8Tzqc+-u$4Aqw'sԨkݥgn vyF.2.b}T7.͵,Ix\ִG}t&!x# -u%Nk0Bo9(H: U&.FG9Et~|ҳ19)ԓD#!+~|̗`9Ӌđ3x%e5-c:o9fJ澻@X _' Fj(Gۿ7eD'cޖvdz̿^Ԥ+ QӜ`% 3kѸm.ۙ<.PORc)!S5偦!~ s0 K ȨaŤ<S[-.}USlr]Z*-Ğ$$UUƐbܘ4@x6P8$ qѭ^T9 / !@WO / [Σ;Us} -Pݕz/{pNa9PqȲU 4cbvņW&Q (^1t ctF.<{G7>KM-h =ȘSH?j&xN3u|~`IwK["ÐØ[ chKDֺ&}gK77 Tf~ӒĔ4H@VM B{{U;|\TNo{t׎$ɺ4(5VF$}x]*IqAX53ۧJ'./DEI Ok#-XT/C@G'0 id)gL nu>T۶܂LdI Edel']쁉|~$&G;HWmJ;\A{k5K9H" eլKr !rn|˒-&m0as"X9uL9muDzW/ [S 1\"@Ljߏ_VvD<4[h\} LMyy_+Z`Y!~Cw?3NMGL~WĀ_:5h pr^:%I sYGgeR(c墌҅C6 >"8u`WrPpu4rPKOj s5w=~4?nFU>M b2U-W|2;,*YB\۔hO" klyx.;4'!]!5I|zg>VX"=ZusM0…w lJS`q2x6A8%z-yyLUg[GxL)2%ŎWU!=C PG3 t %;k/s"Xʨ%؀YLN oojd+C\O9a.u\߂ - @"a`nxߘa+×)-4^eh}zSo G Ev)'U =K7pٴv*#>ל>!mh )ܶyMs0_&EՒ+TY=N 7py˄\l]vTpi?-ucC,O(|F`L6`:uxoML.S/ e)i? >Så6:"R^|"!>wb<ûuj$L͏Xܖ~f0gUɗ*!/}.PGt/6ubz!12J*&8tdsS.鞓0hwƚJ -Iͧ)i2OB*\Rq4ՊתW <Y-px <؉-&70b5>7ߏ5)<BQO| _tգ @&wEt"NNj!g#e<~ ڥTۺ(V}>Hjl2x7gXy<ͥCO ݅V^m%敖dB@~-P՚zݫ3z]+ UVx1&pl_tp&,?V,:g3|:=bN觠Wɥ hjL:  .\d@mlkٴyx8{,^2βH.b"gu) 1m)OLmdGtY9mIGC T1ѓr GM‘l%MAͤ+s:{ڀy/18bn*k*HY42:4b⨍\.9Ua!Q#.Ig`+#HvѦ8Xaua莳5~Ą'W6]}]M+|tdP"èDF@-H($E?7 q=_IA\U@ab\yQf6m3|P":!~Clv>a[3Z.l2Nnbtߠ}w|1iXrv ^VYzѴB5ݠ#i0KZ7|:9ja[\;y{HR½&䊶y9#ecbyVuz%׋IRٵ& ĐRwNZ$);JEq*]u=7L(AspLݭP1;:84W?*Rl %w+C}?Ivwa[00OD:W7AnI`2+Κ@OY)WF&Hh^F:=OrQ/-?WބJsq gudD'Ctp p-Y5%_DԵ!P2BnD&wPq,˻O'?>tȥ% \TܓHg"f뢭B&%**CZL41w~:l^^є66<*h /;N3;vI7,MJGA_gyey]&aå \0Cefb"NQ#]vD͠FC-N)hL.j0?҂W7 }ʰn|h5;DEIw,ʛї BL2K7*>BD…etJ/3. ,YGރ;2UGH_b j|A_p3iV~ɍHrHO *^l75PX e\:/-oyJOׄ<%DYV"^>Xl#n:udBu Bڈ5ҲH7rSS`(R+)|2yx. !c\GMkDE:N(Ml[èÜہai4X0 Wa}J@!QgII֏S]&WAϓÇ se\;Cc acވA <Č :Ѵ/&^O=md E(mkdK3#A`ȭ0#mYQ2- `4'i 褐(&=ot*&z)+ PmLdD{M )}q A02fہGvEsT@;)qdIV/j% 靲gy,&HLXC^Ej9ywr %ɌE`?;2ӗړ-J'Y)-B2-x*w"eNYmFZ}maӾp)|*%Г&k]KOAXw}*:,2!:;<'ùdEck7!ශ&o 6b;oZ3Ny M[MObQ:l6PCʙC]wsA";y릺3&%8ץmh%L(v*uXd1FqL{@ÇL1eX QW)7J|:+Ѿ5ѭ"/ޅ3wHoUE)XS3teF*"I-2D 4gZKTPnO5W!!|+!d9Y.zI7:^Cdޔ:غ$=04w3?/[8H?׿iRc}{jR,!W݆խ,Ѿ8停BlO quZVVMBE'rqomT[ \Og%)Z r r׶G{ ]ctӫS2%w8␠n&*'HyGVZ]w;ݫ˻kptݑo8ȿ^tn|_zrD¨mMac1цMDV&ævU6O3BIeD_GV2uDG}ӤxZg_tug$ѐ-AZ4mK~[D*d! Nx32 s@)Rzer8LaLZ/^ͽrt,ΟZ N {nK'E)|w9"L =s\+W]= _Lr!qdJl"%.]?C EH5MF8.wqŚOm#4xuJh@]>VV?T1/Lٲ{ee]eTF TλMVfsF@er 'sE63]lD |@Q f7 #PWfV*hMuU,w6g=1Y}r'M?Pm\Kdtt6S_WNz+.o~ el/Dl[-]Uwۅ83A wb9۫uJgö޶6%,0)++D®ȍέ6A5]on+cjeo\p^DҤu$t5Lo8{O%A%lw%f)@PEw UkŔ#T"F]^HXC~ a)-7%qSyc/G(ρ%Ku5WJ|Š8Du33ZKfsk)9ix쮸3k[u}8Ieb`-w˂gdžZ,6sG%5a zWlJKH+޺ݗ N HT$'wtLX0V|%* r<+|u?NTmW(Jc`p䀅27'/-zӰOo&9MӽjpEj,kz$W,@>(zz~0e ᏡJYTK;g#J'\96OZ_g=@thr )ߋgP~Tt(ZhބmD{Vjb.D"w)_ 0I⋺/bI)Vk@3j}NنLb ϴ' -`F+kHe|4/x(o8Ǚ ) s!҃٨½]EPd{I5wdTy%V45SJHdxQA^SnjEGיurl0N$T{Yhѩ#O5ߜwR{tY{&EMd5>4 MW}gc08RhұPN4T3JuIu"":N[5 :ez9,XXIrDBv# ʻ2bFμr rQ `RU+չ Z㬛 Q>ڃ*8xQF'Cn' v/W?rrC87 lք!F` \梱R#fØiAUQ@EuUrg);6yW><7rO킬<%nu"w>%v9㌴U}vɎ@] j~2G"m);CE(PPz:2ӝm5NuվNg 0 . * obffJšU_ `ID{*Db-K*ƛ+誃w~(g:)ߖ{/őtW7/GnI^aEOURQ!݄&喝 @g*!RQ?l8e8n:)}chV^(FY8IG0jV0U:ќ|r5%BsQ (#\b(>GWrl+P `R0`z:>3=/H,bq,j&)Rf5' "/SW1B5lVw]T1bWvƿ)Cd@k iV2X`o&f[ЊCg5Ч-;5%c꿃2 a9A[YD+s)YdY;hr/8R!oz<1pxbsTPZv8<@.[mHf31[˾mmG/Qa&Z;`< dX!fMX໳*unԡ*uT[j`BDn3"n֧F>Kn܍ [UC"0z=a8v_5I<-֣v2x, <P'n5|{Ą_wR<@^nl*Kq+Wi42QGY00g i_ف8:WFd!{z&OΖ+{!{Ús>tC3^ ϸȄЋTS7I[~ml]SZ(lꪣ =77샢pgm N1 ]iaâSZ;4Sğ^g|" M*¡H\B0gDvQ(;Վ,sXY x}w5( 4[Jk: m$(aL VzYeb3\沧Xw,Q0r,vŧ9PW%4e7៊{_PN <% E$H=gPMӮ.:/+/mKdr;B(? OBabFwr <"Lz^8 ?2W pt0/Rܸڷ4jn鈁Z"/w 1}j\jLG ck732+c( 4:~p,6PpD- ;8w 'l\8739vXĞ)xTuBYYVhiAꚁd#(}>3?s#'ӛ :A׭"~B.ͮ&,}&1Кg7Z 3}x v^qKEzG?/?ά 5so5[CEJ5B|.k>*?(:)f3y5ջ<>"paG]b |z.x(/N}x tA4Rչ^ejͨn RJ+ݾq2.z뎻w_+ɫ:SڙxUc 9x@%C5`N=?Rpp߸O1xa깚:BA;!Zs2cjۙ-uwūҺ׿gp(+DP.l bZ {R^q-gi VfzQyfNAEℾېv!'d]5ml~fH mA„(;@U:jy'+tƓ ri$3e\5H0u^.鴾/ !MCrҦ]êBȕ`iq!qJ 6z3ڪ4z<e:\ӐEÏf6اCUNv t~-ɭzւkR9o#gx7-T{J $sM,j1+ ho؂n=vܨfnkќK-L驕bL:#G[j4\at3&3Ruj4 4]J{\D36;d]Ip񂜈[XN²ͱ_%\]ֱ~g!㓬zO7;-!.kh12A]V=B߮ o}:M^֐xa$SL7"{u(Of"@*\'Y, :^]zXgԨE֋AQ[~An.55eK©(f>+5Tx3ڨA;lCw^LFxQq"ʐW?o_ŸƂGqFW$'$:O).mZf-!&H+8=HEΡ''Dޗ6Za%c<ۣ_޿jxw !<!b'v7% ?9}bƷMVՕ5H؉]濕aW^utXraR6Gn*`@.Q`v}jB?sK<3a6|Z"(KxTzi7eN| 8oé_Yoq@EY $:.*):<-:xDX_-ϋ8Gzl855!`@>OK?ы`zfS d= bXreC w4jX t_?`!բT?)9{JȚ#sk>zi0 KeD-> qJ!_< _#Z">E͍q?qc͟p养Cw !mi5|19%n_-pGDtq=V3'ZMbF =a 3mS_͹k?֓~߉OBf&5[ڮ1 y=Za@C$̰Qa$~L77%dW!>C%(m x[TL&{ʿ_'08Q]QmW<\߄uſ/ʟp{9LJ-P.>A_u~Vˎ>Lpu-@''ЅqVuW(ܣ.F:erNx6p>ܓ[YLabҬ -3V[/1qGٷ _2{qlA߲F!?2FY |h qdqݺ^H K== .ل}"n)hH"H\ԑySQ=&EsmߓnN#?`g&=Ӊd} BY7265 "Hy[!EΊ@8[oBpAycb )f=oVx/:=~Ι28%.n)l'f G5@pPWsy *ߝNO9-Zh 0hV,ķIMFɐ0]Rp*%ܼj`K>Wtsshmr5f2*(Hr,Z6rVg:̞ L:*Bxl[VpT/*qq@)?TW.l%54*k`+Y?.ɨ4 >XX#3G߱ /L”i?fTFOc1 =zmNIAl8zfM&``Cc6)IcPgHVgMz5 S_]P5rR|_6T-?WJ\Frʱiў ^t$?4C=\7:.8/CpzAs:j*+ [ݳR ]o@wlxv #n[&HUHr7iVe"Rb*tԍ7YIusoX0 S4nu=a*Ϝ j,]ϩ`9A,)*s_F&aWLr O<:5rhV\?s2cnp@)p_śm(a5QLa*O&zoU& |]2]Oc"(z OrOU^V>'Kyt!^sQYOt`$;)_cnN3ϟ sG`F[񁟧/̄8|,~.j2WEBO[\-O|j򵍙T,A ҷ<ʃ}t>YԽ(ƓnɜG"lNw4|x#Z@kn9Cl%c3B#܃dxJ?(ױXzsۼDZSKSЧ8s[;FFζ~pU{ [!l( =(cxUmEyV >.s8=5NDk'(z2M׷2I/140ѕXvn!N98:Uʼnضjbi2|`keZCwPܖ/sANr/.u-$ 17Gf }dRpm"ФuA7PՃU(G_γ5- G')[^YW؆+?.ߎ{=5Cl[x3_S8ҭ쐧IɄ ûiBXYuk90ZE*[15m>bdaFIMC`qd15ɽz8YMOF@/OyN酎^=<{ʐuOgX2Ͱl#2lJUoa#.%""19Z* YOIU9 ߥ؈`u'><^,vI>d'ʻ0v.Fǵ<gqJ˞xE^2* {Q,ʍWzj)~irM;Ꞧ_U~A~?W){J`Ѵopl׵훋!j2gT,+т:/Z6*Q _ n$32WPs{oGbZUrvPvuf0)8G{ K@N#5028>u 7)0dmgβiO'. +Zv  Ojkj]vqCgJUmԃ 4=:5̘lF'jQ(s!yM8{W"#r#Wl_IqQj$Pȶ$^yDOjYU-IԠ HSX1yG:rM/^M|vhFr6׵t/gYjd̙`|wb~97MVţvGX)ӑs:1v`kp+Ҽ*G=Yb6=8r5U"3#uV0zS; dۈ!7ՕvHpҺ O+ +r- ]Yex3Ư~8nV~ͥgIK?筢bo/yKez>^s׵;eA1S`xϓ}4 d%]z__Ӡ& Ҋ1U_qBh㧶|HUP\ř~ª G20MKp;d!2LQ ԄtQdtXlʻ=w`zM?~A?~J>k7xh׹, YeߥEMA[f'&q6:3IlǨ^cq@ej? cYhּPs _Тbh xNPx\#3"UZӥ9[sZgwpvfEYh \]4cYLJ@xJKmDU=0 )^9BAnД 9|4xd%&"^ݕΘ8*E5hm)qPW6'0;I;aXXKŪ irCmL"NҘ; [;7`{r2KU59( !_c`b!FO/Z?HPMWQj=Du]`?l>Fy 6=R^DuE {B`b;|9] YZ ?_w2ۺ:vhW~{lH;҇$XyuF8rzw"~ ;FޯC[.i6J]@2&5̞SNPԜu/יNNuKA10m] {z!KW 4=Z}FaqKڽ7Lyb ,L>0IjFA, <ɯXh|BE6YtLbx,Ao2SocQa{?"~뻕KNַAiV WuQ\f =C}WpgQa# +z(0J0`$۹DZxUn}*I4~:wmV1s LlX嵠RAX/%p BSw}:IL%]>3~ue& q"6Iq\=6[}͇T0i\rGcB#o) bP޲[<flS7+nl%:&QKV='Q|l+GmIF u]|R/7B yĨn9XqH0~iM?"xSıG {흒WNw-׃bºSCJ 뱎mlHK["0X[Jn{uz| ,}X* {φ{VTX0Ab+!qcƇdMeCmA(UQxj:ET#YT"eۤxr#.8eJیMٲ֫u;ȩkecJ_=!9oa]!=Jz8k;sH՛9` YR>EȺi@YP_ dd9KOޢ s+R+ sQ\')}uoܖ_?{eZ[{3/O{E0}.VZ: HSJOD*N恇Ű{/)_\՞q>h_d@6_*qdPms)5 Y;(,#nzhF!B|+E toǽ/h߼(_UB4:A1W SٕȰÍ(Y&PxG! Ƅ!|h>h)N=H=DL[ONBDl01&1A/_ND,9|'~YP;Qf>c^3T L5~4S3A`d ΞSW8}ǝa6NlPP`GHD3`X4ߞJpkzq8a/dž\@*sz)"':E$?)bQf*Zjaxg2 @BgFU̢A{@Z-@S-ߋ!!3~!H0>?Rg1~,X͛P:Oy_pxĊfޏ"`!*[@ʥߘ[rJFAstD{QU=swN4jTNVVؙ %;#`9L%Rd02bH0" Ő"ȉ- .٨ 'brd(r5r_0/eQ.:ouBi{vՠ'bzcP89Lq4!ndksӗL^/<;,a1tbΰ|f6SFRՂ) S_='y gXrhRFڅ~-b.q+bxv̖W?e=}A8[ WnAB)ԋDRg&m;w/IX=r-lh/FEoQ,s< @i]+wQxB~nIAA-JC06ȹ8`$"ٽ%im5º*W۶RzTo{I&w5/+;UHS'ۭlxBs*V3Ics LJ9><8SHKȀ ܣSvW&4$N6nz$Yã; ؙ 4'jkbi9lD^莯+{ X'$p{ l;M ݘr)y%_B,\}2?MD۰"|Y饃|Yk ܉]~jǹƦ{xh M;P ķ >HG 'Tq,^,t0mpF^M_iɓ.ؾ?$aÄK>S1K=o$ C4s2212P爘mW|lQ|jA!N,qAh<+SLw;.1>iAma PA\3O/ ފ.A6wLW^B^-gw0;P+AH&0Q+ @XŶS貉LS4gJ-? ԯ86 1/ 7T -Aî6@ 2A Dd5μކ#ƛ3y49!J9:tGVɎ.Gk`Q C9$yzJPP !EКTf46 B@ U geĮ.]j\{MW ɡ~Xo%ao:xkWeW}.dt]va `oSV/xc\ն:FDBmѰ\Msh:."nE=)E}H{*OoWVsO1Ȩ: )G:2Dl)}=GPSt#ǿee¯I|ЈdxS31'J!30.'ޒ:'?[suFMކ]&i{.B8 Ӗ '?A<'{i;O Orn 4nh1AȦL`2|8V9] O$2a 3jB-zu 21E)``Ҡt_B Vb|IZ014|Bdqaɡ.zLގ_Ϟ ANNbXd3"m3\ [a#clFy"v)8I$[:z7gMg6Aiitk,A'2d-MM"b%,{C:O.WڑN=!aѡ%\smljk+}THהּ//X#75pEB67IP8a?/&èljgHo>HK~ #*]t+O4]b&ܯcZ٭Di0lSo7{DD4ie\RXR͇3XD5'b]vjwo}RӲN2 ы[8FleZQy)qT)²c/dྑWX/g@O| aBuWI g/N: j*08vmDZ.~ iX=N1SiD`ajl~2jyDơCuTqaVG/& @"HcOiqKgƓ_$FpѦXx2Us!H[쾦g xTvmJJC_4_:Kҭꆣ޸zɿKF>|ؕ4gQe,0 ypbm?)?~"WkR?7]ٷ, : G|$xы\URd/Bn~pT>? *:p Yq0YKM39+m.JK̃["5`" 4>q'7=y MZkja)1n0ôJA܂ǫ5˫4)jbW ~"p\ic¬&C-!ƨ՝^1$q,)y4 V )uVo~TX܁BBxۮclj qM[:MhAT==Y^S|FC9Rh/o-![8ybQ P>pQCZ-m!pcW+}l0vI5+.hnD2!( {-_E5c+GxOamyWCf# ߙc9U,{}|GRu8p"RkDp q]8E{RV3_6Ru3s SkisĦ7c8fTݗ^dz=ZtpN~5l;~Ő;gh9oEnepD\\ւ{#i5OC i9 fɗ"f(+~*L^$~'-nFĤ.^8&qAd862mgf,H{xbz/KiéisJ76&i|ĕ~`ot!H6oApBgͽf JPj2Z2_hzdYadEl3UR v4~?H{,q1B:{85q;SzD2%Pu11V8|.VN1Y_'絴& Űٛ RS"%_AH! 0:DY)0\O_nA6\o/$ݹ-BnKڜh_nV5ޣ-0ghj8JbKs=-z2ɢJYaps֐ddV\@ź A ڔDfGUIH "Yt*N$#[_v!([qGkJ4T+MC0rfQGyhm:G{3t}3ϱQ>S~v(z7"q.J;^˃[i*xχFHb ֠T|rs_[q{( \M,rF*pD|׉:ijrԾ ڸtu25k<$klQ̃`X`6d5A踫 #x'Rt22WH1C} ݋[vZZ?V)0ҵ83 JiϦ0=voYNl1Y0>0,Q<dfl0()R2  Z鎇ђ$<N"5byR0Od4ڪn{Ь~" ׉hIh^#"8L |8HG/7ͼw fd" nx@A'ܺ551ny XJxn$ {:7TdRN$=Mľ?dZɯ<1 F.& ^87 m}ٷMU;iˇ@1 ^ ˉcDyv+枟+;_V+@~ trSB$!18Jx!$LH W0, 4VɅݵf2Da憠ř2%̔2CHP~-&"j&ȋ.gbƫw*\w"ϻ?6_W\,*NɱeȍA0fΎk(D>S5w^n`x"D-xa dDCd^-Zk*!hG{u) =pWTnj^omtM{ fy'E.D>KPzrɎFȅ  ܢ\a),]Pc=HJ$Pe72FNX ͝l(I`&C5d6%~P}^H皤nG:GN_qc =S]-$p@C]L-\+Hcdc4JbVcL9/Y/x?Ԅz5 P=&TwH(YNԪnɱ<J|3-rrع-u[63O/È-gbUav+ۜ=2##: 6QI*|*8PO~A}87/La>:iJX7 J"[L{3,ۮ4b"SYqLS 19j;͝'+AOM{tR(De^/:tݺw4Y4Jvܱ.8O7J0n{EB>WuVq5Fy^PmqtN𮥳`:Ī´E 2ᩉALeY"G;"A|HO/v;sk}dS~b.< *XÅI"K8={9@ GU C΋ pYwNAF\^Ƙ>ך>8e9.HpsJ_ ۈ%h~*}kv)-ߎ*鵢1YN@VgZnvL|ouDžx `ge)ѐe u}$a:ŗ(XeVcle_m? !fc2Wnv:/Vqlmcst-YMiXq%{;7Qt5`Yz.akzcz /K"?}6#`b|*4Wo1{6.؄  6=MAVz(xm„bsO [ipô:X'` b/qA]y!tN"C͠gDI3gŽ{9u1Q_io+ RDeҎmA'w{DÝytg֥[#<5J{>q8㍧©]+L| ՛ֱ 4*i,\BebX..Qlyw@E)UHڜcp[?|}BPZ\ v`hh~ٮM 0qe@ͨzdh* H;zR?}m2v#j;:w:hCѸYIC(Q-M@;KzjzBQ{/3a/D+6`.1wS#$! ʡŹ<8O6& G/'ut_DH51w޷W@EWalVy/4"ҒYMSP)WĄW8Ac{egi3FU9' Ͱ*޾<[pTġoLVĴ>}q`cD~#热ryN-y&L0) Q0bmZ6~(RACEwӞ=@Lj? XS7mei_,] z쿐j!mݗ|f(ǝdž(:T0~t$!gcX{n^=;L2[KTK:{6c&)n:o}N0ps}eSnPUخZļI3DO oCK)ng?#I|NgJ,#%,Owto*f|>/Kq GK@_OI/1DZz66b%wj%<1\aXc [rK~o@SW!#ҽUgHj^Æ ѣ;:w y\TȎJ\jq|7,m_5A{6T4w'yndMz,LF4kڶ1a51 F@XX1.c=E"zTksyE{pzQ+TulX|?eyJK(]q(x_ݮp_lFfVegTA0uy,&vq?-6o-T!^u=*;.<~`WOWyuÛ h捏wҽV=T \TzQ.q)qq[L-YbNbnlJOW`H0?Gx[pO)kE?WRIӆ=7Jl<7>[zsYޕ>HiND_1*o&NfEb-R9=.3Њj;ETtM `nF ˈ^ ѡ3 i+IsX$H<ի-~k]GMaOHJ* };ѢU!J憎DZQDŽfb9i=f$kP^Z` 6-8>e,P/d= 0BbW?65== T˶! K j8iK7~=wK0mPCa 9胰Ò$*u9T<׉^ߵvWVAO d_#@TO u~)p9F-''Iki=יwM"oOϾ=}βhd a0:d_^|+1،3aynعFiX>J t=.|0oЕBO&p 4{soέˬ}^qg#tJŜmޤ=:YWu(lE0&ǬI=ƙ;tʺtzx}MV< MTe Cd#n[/PhhT f45 ({a>랹FnN/thԛ҄-ϼxة& H] TvRlrfԞB"YtֶuSe&~wdoP@De3? ZbMeH4$, c}fieA-DUXӤ!h憎^  l}}oz ;!zskehDr:n=pt3(HG7?Ҿ`l:!2035#io<[Ԓ\ f;A9ә!0̀krVBnW^Oqa Uj%c_2%Bj4jŒ]\xo)u6E?0X5H/3G_i>PO R`;h8#[:b9Som<\SH-c/^xc oN2v~Уj׵ȃ߯й71 _IC3f9nX9SQ-fm?jy8GuD.$8 (*Mkbԏ,O.(6fUv4nzh\5Z6{oq1+L6 KzEUtNV| LǞ\ 6J\lJ};@_qiDD3p7 W%EkOWDB8Oo:+&I9t;& y!8[a!AH'•sj/Šq &p;45GQ8x"A͐jiptcAXo_ʼn*U*$A=0r/oTtKD}$'41WjE^n+Xs=kZATs%}6|ӱQő3sn{'oe~uyk=[[#a:)?Ae Bcnކ*m7cZ:vF|rxZ%?ޙi]bJh:T݀;`Ğl&$eܿP kEIASTQtpu<Oh=fENP|b&=V؞@R w7Nx^ k] 5M{pG)>i'ݛ?zKӯ"Őll7a27klR :7*7XAJUL*Sͱ EҍAc[c }_>q)QBPZ)15ylS_}D]yH^:}(Sayϩ=hjOPH^WEDIޗWNl9ʾad58VPÁ<8~!]J,(P:sO9*5.t`OY>.Ęe.4%$ͣ2īlCۍ d$xd+?:wCsk,WA { _1K ].ۯ]^Slr)&Oߎmy6-fW]7u#={s!wbᵦў&%*t"bƁW2QlFu RY(SO~&T$[J *Hu|aqh|Ƀd Yta P"_roMR?p3r%2Hsw ^i=;>HJ[3[QU21{m*/4bwJƬ}|RVދAO5ĝ-iK$.3A$9 #ޙrۤJDINSBYmλUZ`Usޝ݃&0K=fda2;p`n`j$al*g5f[ծuڊ;#.Iq#kiϒr>bd%"574JQ %XG&!6p`7l\쑱,coOB$)"wcg}=ib^j煭.\EB=SzO3b~<@B-h8PLs k c $b7r=pCJe>Y \20T0mNJ]GtE@xs7eqzYY|4V* W6`JquxrV, T!Aw}0.F6ׂ:I#JdJfv\:bȪ8(e䱈UNi N_=^仹fk3 z>]~7VfT"ڝ?_7 eֻ!Ho3~RQ \ja8J#T,}HcAi'9)Je{;($tA`'%<ݻh/I^vaD&n pBG7ݨbbgwWܩhzPQɟflXRR2+d:L\{2?`X!IBybA Opŵ 8b8hTYNLY՞9g{\ߵQD]i :QP\Xv IG{tQBL@ ?/\2ʑwcVȏ\L.%Q7T-}$H%h5Ǜ^ܠ& ; { HXj=^bn#4ʩB,57>5pixg7Kİ'~fIi"zpy"]*JrگFVb{Y CE^o%JPl#@2]-apPe mu! x݋讠gGXzjr>_'J+a-yt)SJM}`dړIO:fxЯh)_/`mg8gy}b3zUNG!/X [mU]f{O Ӎy0 *Kg-h4N4JF2 .6pRALA骩~TRK %~yO]ҕCWMu:I5 &[iD?,kQ3 qH`qo-ZIbrD~q؞I<4 |?ޯt몁N[?w>ٮS5Q0DN9)G83hkf S+{,QqJu\w}9H_˴噸9|&jw"cD"iݮ$D #j ?})Nv| fg [a0M)e4MBl_7v;V[ 'Tf $<U 'cը4Hcy۽1|w`Ir^Z'UwZt%Wsl, Kg*eh^$7 :;Pw"j)vF} }@՘l_-Ǟ<$R}Ւ$fZbϙn_aEx4y6K2fK-{dty#bG%@A-1YxmRw ݛ2\ ,ꁉLӳEа֖ywPkM3fɠ2݋6ü du v'd\"J-VۦiD`' 'ZJ/tTu-/J[f0휢7["z;JWj㾹BFMOWmU9vI?LI1;ۏƄ t0D%Eەõٵ && Z{qxv+% sꚄ;gԝA3cAУj.[#Y+߶AC/JJY+2ԧI{h(*~e*dP`Ij6$iSGްnb<؋ 1ηd# x҄0>n・{=< "2RPnFT10ȴRmDT(**%|UFιt%+N-$7OK6sNkAIAQjyboeucޒ{%QtJ栄TH.wHhJX"ujQ EQB62,<b֠(Zk9Qfn#Ae`R&32 "M_ꨴPoӧmOͩxm ߢݭwcPZurwRL^z^`1PV/ZOrh\ƑI.F&%#֘A1>ьNlQLCj@5weҘHLzH\)PQe 8U)sbBWƗ4bf <%\l{9d< S̊5?:ѯ) )$3}Մ2%ecYs:&Ўw,ӲY`~m;iU[{O'yȻ7ey8PmӲڎ~b&KΔ[ណ uC4hZ`Xa_;3Ϟ} dؕ/Sc|WoV~I.n+nm_9: ta6SɐN"0ݩ~%>4 9:}$H,z^5b!$$U<%xQ|2D26FYg|qs(#@  )'TMU WN#akEU_CekZ53ᏼ{PkH>J6>7yS"僀wQ gh! 2Ɉ8Td^M3^?t jz9:KJ. Hv,9։AlI|7ʡWaK51pGr"3mK" zcu[\=IƓno @GכK>ֹ;}d?B4UBP,Ql۽sUqTԥYS=e^vpaEvi\TNz29-p'v(o>6,5mt'/A97DARZD'Z0-EʭUY}r0UWmEF5=gI+R4υ$s:Eurj r#$RYX /T8a*P_cCʲ1Tu d[Kbh&Q0OIomk)$Wh}u ;}dwMb. xvv{qvip?&Yۙt hkuFBv0 plPrS%qZ` Puu Mm ߝ>PcJD^TE<:#^L훯i \2jHH762_~MM D-5l! n`9 AH+W;>$+[%6ixv9}%SER'~crdc㾗i{-h{)sq} (g]nFogݞ n #nU]-tFF졇ٖ-H8sDF'PhVa2:e5/ =~N+/PYs֔5;̢WEx# .Sm6 RXU4ɾww/h=n1:#G<'*$J)%J<}Y.3Ίs8EܹnOXu>_7Pn*vD2#h({s Y{bp; Dh񚟙s"J(4"o~B㷖r~@C9_8?V%%+%"NvfdnHWoRX<Ɲ\HXsE}-ӄ.l/x-AQZ"b< 0]Ι (~Gn!T&<>C.jT+ C',1dQu9T~%>v=# ʐ'E͇f,<ES2 9i"`%Rk8aƾFeXj)%ϋeowa~75Sށnwej S]7#~1A!nУk~d)!GbS!βy0hwKҚ NIiԻ ֜ɪh&4q#Zܕ mF%I{9xWRlTnեfgY.Cҏi|=~0g:tNG sCoT=?I/Ցn#{w-fx bޖ% j-gIx=g`eUv xL^5}6H#X^JѪ?"1 [0[HJC,YgMKqǕjMChKtCs@Ztxq*QxC%ϲ=-8R2$(#wCEb93' GH s \fm:Z,ݣ^(c b@A`x=a$|rKqO]|Xmg g9Gy]>9".Iϖ=Ҝ[dOՉJl*5n_3S&K/[b*,¤uLm߀rt߲GqPTO@98GtMqobLU*Tl܎Rj] u=9žvy|pXb2z#}̼ vg y`*lmT)Ey0;N+߷ؾIcQ)usm*\ r~XUdZӘG5xlgNeb wRʔ^!@}aa:fB%jH/̌x$^큞i .D9iQEVg(^HhCryc8Ż4FewX]IY4J˕w)ёZdgtzfA<Ȍ>=$l੥I؟e+'c@ ֌cV H!;xc3L{*aZML0!,k}ns9 ʫ";ffꊻ6usޝ: !&n%-Zˎ[N @:~>s*e+$: 4qLdӚf!~9 NY[U$6ey%BT8иX"i׏3[tPJT]s؂={X~6^!\F X ?U*+(U*.şٹZ x[ytC"|\űQeƍxpESUkѼMMzڌx N#JK*"*}m]Kam*$쒪&7i_w9:{&t2t=x: Tq6hPB!D|Mȳ^;b'8<0cĩ#r?H o8Cŭe|re~m+F48(pO!~'mrʍz*.#l : r8`k1mHV@ ;+6 abbB\]j)[T8B/"A)@Oh ?sǘ )U GJ&" rXl*̙$X]'~Q6ۧ<[<7ߤxcC%WL6ܫ093`YnTOrn|[BI0ϝ=σVdwa!;_~^njP)YUW3Skkƽ]P !a5F'Tz-83 ?Q^@;*S9hp|i=jm@+6b22 (S dV@d'i'f̑򺋿qP8JsQBlMwd XpY*m=P}pCI(\cRozz+lǫJpo83ބ0lw{"xJ'B2y8cÈř\C50m/0]}pn4€O߯q:6C[VLι Tx8n{D-9E D#b 0P[ >{oѲ;W'2Q)ɻ:JQtȬ`e#7N/3Ģ)`y|YpT@8%Z.Fy` YQ4QzZTZ(T@g'᪻&]wSĴ8aÛ6fR@o{%< ڃP>ѻYʊ`iCS}r$kXgQi=aiu+uIxhPLfpiu-kv%uMi@D=vN'n%Ȉթu xGx½ZE96+ ]3v>b6v˪ֵXr ?xVt>,E /$LG9bC _Tb¿stHc p_9k|(ߡQ,(6=Ij=+`,Կ'B37` 9̎_rG/TF^lƎz~UjJ?ӣ"xB! ]gԒMܜqOB`x/׳J¶UMBv\<|?0v- + i2jW,gu vy<`ϒ<_UkֲkV0Ҥ5p~)X&S,:2ޱ㓢B{qMȐ9M:xh;UE踓~(z`?`4[δ:Or 3e<"_ ~朲0nedkLW]IC6yqխ4uL` UA;53#I;؟w\.f#8"n6봨eRTdgׄ{-@3pk!-3ud9Jg f 6)7S@}^;4.ޠJ޴^m̲1D {NY똫gE!cT3p@$ĉĆsy (1fE$kja^pQsFbېd(3ݙ#_;cqQbH74 O ٺxdeeg활J̪RD`6QvGj]d qo@{b2t-5{ =Z*Pħ=ZiOLKum:tH^ΧY]i7"r_XNFk>=ÍweY o1[cܜn 9wHXg1nOj%paXBltYWݏ8Xz\L8:߮Y8j߻F,K7"`F)[?-vel㔜)S{mn w {G3Β^}ɚdQ KF\ߐ0ј->ղ{Թ mZfIf2%yeG'&,}\;K쌲 ƪ/ۊSI^<\%]2 v8L6Ikqܐ5GK5NuM>' S>kl宅 a j\@^.ȼ[E:%et$qh ?nسlE81esX-"1أxLO*5WEIq UB.D2+E Je`y{XX ՊRjt+pPyi2@4B,N@a YKjN'Fn8]:ۓ#ʅp#|-wɷL;_78,OI ʂ ѬZ^m9">P̼92*ۏGHD^ԡQ@cHf%Yn4G4;h*[-iBteg/d3MbHcf j*£pd/r W89r+FǑ}"mى( D8<ܾF׻Z'M{Byqp]tցLM$ t|JM &[ 9!f֔GisaY!wq|n5|SNmlL3$ Kzʼv} J 3=ʳA#}2K8H.&XRahu+=%axXsXj2үíHwOIicHC:y)r"la4XEgC׷ݧ`K3U3w3eDžm#(- H56+XW8ҹKUDmO&sPEc3֜u[0ޔ}1'|U# mX{_ iik<Ȏ!P|10>x:@e9Ӧ0qfȀZ &Q#mwz2bS{ jZl9y{ !kqm BBUnxHOu ےZxR8%"'_Ow G~Nm&'˗)*C0UJwx(۪/`#C&=, {A,|`c9S3.WwmnaOi+-SvYי$G5wo}IА\lpx."*Ỵ } 𠏼 "ծ3R(WB!:@^tjD.78UouJ1|(ڢ4P-sVS]wG躀w3`zxǣ]]1uƱK8PbgT=Q܏7 p2U1*ȺyTOGC᱆WfЦۗ9XfE,(.߂^M35|#pbu@py7[`.K)~qML^p]cKg8A);тO4V_v%' Cٔ`0O F2 v%IdQL9FuY\S/dWS,qBU-"-!/@ Yr_}5js7 R2,FjI_ V&w),G'fY-(2#Of8 7 6PMP s

s4 1|pcb FOjFGi{4F0ߪXrρV&j h(*yr] a]G|+'+jD6p 0ĘSk 7m-y*P9 [V;;8"*[mۜX ǂG H)L Ď*5/?8ҭ:AE yry\q# PF9n8|cHGY H+*JβR$;7)Y)ף7{BL( JSV~OgFDbD$.%x<,֝j.~Js|93*=Iq s2=9 rv f4~>`'Wȧa5, Χuc0qP!=dDd·0 x<Q{d:KJg-!ʘbdrzSK +O*˯cBL׃@ Su3^Cm6}73,-ݠ <2-bTd4+y<՗30kBA$=k%nVxˡ=@K( =7WIdFh$^j|̅>ES @6_Ӈš=u钯0%}O~\yGD.:OwAf LE ds6JJN8sWI%T+C/K>,]Lni}*Vhxk;n7~@bgے,`ˇ .\lU7e풟o 8:̖5Hq-~Мxl6ϩG-m׿GFؚ+ri (MDPj ??x,7%ABinA~V2ot .1R[9Tl[ud՚i?bF)ۣTydB1 l(vfsqm# \3]X 2˶'h*^{ Gea_t9 B87&n_i]G<~"J/f:M *j s:\~rvKSj?`^3̋$CTɺQu#UKs?tk&p1XZuB -PH.aRH&iP/]6x]V2 8ÇWa({ *7]fA/ooQTg@7MaV%qV*ъyM/TGL]buQ;bnk e#K :V ^G}Ce M\f~ f QPpna/ WKZ3q`LJQ(jp☱܇w]ghDv x2-ChL^`ͷ@ Zx2ܝu_-=PB765<`nUFZu\$cMۏSV(銫uOo8NZ X٨?iHsE0$ܿc A$Z?W2i u@-\0l4IMblBOkXgo;<@S.K7extЎ^ˢ _+0u/*!?I!35i|c +K#q4M-{'OvS ;Bd(K)F*m%r#(`oS3uvS yLzxۋm!Φ)CCq2_hB 7Lj.[agD[BwgXiOl$gsۙ{[;eHB-G(΂hN4)ҸN¾^?-/&2MjYx\7#wSNjDZ O"\۫dcnE+x,N5*wY ؜'$=1[(yƃ/PlGWݠ+JJB G5;>5䷯P!"%赙Yz-^G}&7>@r}{l[JLV=[n^|g0[ B ߦr{<ɤeIw,3ި<C+Os u-h!e48_ w擳FOy|8c^b+lW,?Dz^/FP$xNh^A\+KgmRC쯊CsUW,=pW᱘#]1U6_ '=^BoyUE@eK%)EE8& ? JM~֊|Kv 5n>O+hcW_ze6Lk~^wkRwCЌM(*e/6Wu}8=QXwwozlq- H#~#>8ɹr"7i, gkj5n޴XܗeT4*Z: Wú$l$ֱ(CQ:LY7%VljdxO?*{,~()e {ت!y r(F]:.^> T$W[c-o2nԳŲ00. B3FS"m|fڑ$cOxy',Ttm[o(Z{EՀ/iӁts_xc憹[=T +g)g^C@{j}2GGc8?&ʜp{=+r{U3W_]in[/kкSBy]EEh@j/ -v-ERkS9[#M R~FoJ 7H<С֌ ta\ 颅nĹ^ c",XF~!e,')xA\kjR?P/˕+a /]_|'^iq{~zD-j~%6VN\} 0gx]Gׄ_U2De4ۙ䪹KX<.*Eë|`/Ŷ}_8Ʒ,wj.*|dWiX/Kdһ|S2rMḃb @L7bͺҭ&w{o~bWbXa61 XO{NkI_kNHn9WQߪLp>J)$d0,?z5h+g &Ei*%sP P43R\$c;+T`4\A~!RN SFrjPߊv~kUi llm5F&ޒf*JglrVdjA54G|"bfzk HZ 7&Px{NDg.Z90؍5$ soBwE5JuJk֙ :D@!*M/`PjM$549"򈈻Ss6.:e֥oZT >^Wx\9B-|b= ^w쁣8Ml9Nh˟Q+6& V+; Mkl'?LsS@3m|? !4><Ê;|T݆P>EE6'-Z@tk|~tc\N hV񯩢О\mRʑE_3Djj}Zؼ=N~NGjaN˷;5ޝ|uB8#%}YGAGg85{w/@%:x9<^)O >ǏQQF3F}U|w10 IbL$8r'S ^|v13o%_ oɟazb `|4nkTW=Ycsݹ`j۠Gc ) nn^w9>]LIhy+rn34#-Agr];ܐ gJ @k0SʚnA:<ކI-ͳ{P-MnϹ182%< 1<1{!OX]HKHXt.LWouUQxG<}MGG+Oh܁ 4\ k&BԒxn2VNl‰|=(;C˵ngb E4q4K"b.1h=~7Աjl4b?(Oykޱ"N {jy_4`|\k_@eZx+R+i?H2b͆-ݐ1EM#ƥ0w*ovۙ]\cx8DwC,шؚK_BCJr \3yw%U!,+T\^ w%0O !$y-R P!e#AaZI4w".g <KT_]28Vq\{+%qN7[0x9"`[4-7VǙ @okӾp9GOJM{TJ8}`'JƱw4QHq@I6+vؒ^.l*QyOaXǎv`Pʼn6=?P+Q \-4݊ЖэYj"K%S;=Nޛ.٣i':Ak2ۻHYX/w$h^ƢjL, *۔>Vðԧ:Iz"CP&a`+)؍ X!qRՎFKqgdL@i̋YtuBC{$r'YV Z|8L0 2>JJv)征 /ج,.) ˆ ekȴ⭱ߧs:;5"x-q54BBe#,}yLlT=GaoZnk_Vo[Y;?sT㣚r|LLP( Pdx^^(]`cG*J#hWCg\dGl!`m5dFrH{RyjYr8xs^Em)*@E<`b{g8DhE奈 B4ѩu>G>٧f0&ض!lUP叄Dp3\ي1D$ۺqbvO,7V,h5JO MZ>dz@=-?'8o1cɠRķy^NHPќ'&HXxZ?(SMuhtݗf[>a܅x̫-s4xaLEcݗH]umWiwN5cKe;L깧 7MW8i.UMY'dYV}BG$4.K|wR1WarVg^m M\XШUA%MdSe|9CX ʑ+RtZ&ܘw\X$m @b% FJ9) ]p*u; oGpƥrsD6O\82?Z.eLbNy|>CW^H`REk X]P]"Ӟ̮V[3D#y4Q$/euK咯v_OAʉ_GHu !q>ƈ,)7ґO Iٛ@ys~R c$EM;4FD 9_|AlXώhX[ʪ1J)ӂvG UXQ : ?zpg\/*( _K.M,ropNzFm1JP2Mr')㉎z#dɹ_1m"&I8k`J}˽v65z0g|RXǡ;Xd@aR{kwV3UlڇKZ &%,$+5M5`J7x]h Q^_~ &wT&.ߓ_F|U:ٞ,pz'N9CGvb*U8$0/Bٲ6!{*~;h^c)$6gЧbQv%KG a5k8T<=~!ʸNč}4VЯQѺ8Nܥ6jFUjV;wg1*a҄$wj]+¦ufy1( F pHqe1jsID%qf 0a<9iU!3VL|:+Ä)nI19vd*QP^x~C2tEP T&;%iCHv;v2\{ca0TSfU4<V© Qj@ʽo~~}XWu |bCIdR2:W ~^ Sp"i6آB{iXo7ƽ1aȻvy"$FݩPBtiG;:$] *U&L=d^4 Sĵn".l O–]5*VUjjԳ1L! ҃S^g~Uъ"~rQTzL pT;ڜ' bK/ "_)Wz)w;a t1T8.a ۝n֨nA_^j-:.N\]tXx)O\kC`"ބbǘ`+G؜N-[/„Y&Lg &a惑yh2Ћ8&vQ1ۘ יo+BQ`x Ơ$/+. RT- LlTNx7K! 1: ]MXR&(4a#4sNݭ'!r쯞zU@07 ╠Wӱ%$,J\Ǻh=vgCRxcvT8'i.{DEϲ9|L&S9JgPHH[O*GwcHKP$[FbWሥ7i1u4mZ~T-W{c%&P*׷\?K[_(e9>VCF{sFT~,/ơEX v7HSG j9M7{5 NwDqV D4,\E+ B-lS.,b4q7jܲJԉX'2J}`O"q7؈l.YEBY8xq'|5:8Z*bϗZVc)w~&!!$Bt$k60B<XT\T('~SycYr51j}[80 US0=ZytVهN]S(F;\nig_/rLpwmq|P&-,~} 1$}P}ބO_sZ[Suta*/WGsXxET=C yh%/:zs-j]sjo_ٓD93Bs|Fఙ'1Dy`ԙm7a}[NP5;]DPDݙ佊7iknh|TNJ}n|ɴuu:ti'@]t  o-y&?>w,l~\fp z* {F,#LȫD"ըR0 9+I8R wLjK.]y}4(C$(q.L>*6/'9<!kOܤm6GA9gXcl $~zk6FQҪ}j̓ܟN9}yۨN4`\n+Z-eqтȲ٨B|W[98ٝ cZ3 'ZRtT aR,AJ2m)1rt2L3p_ϲaޟ3b*j̮v܊ :[~f9κ!9' {g#բ*'%v\=:Yr^+!g2"sRmc/i1tPp]7}KFĒJ9]%<9Cw K)Op:4HVP2̸EV01Li:1(=MUшDŽYebqJ4QۥFqZ9ja_u/(g *?B> I%΀a1uWAB+HM;͗dlN~7 x7EI#EJbU6:oX"/u %(9: 5cnЊ 9j8z, īWG*$Oώ~~koP ݁,!,\@ENG~BAQSʑ־[aĴqk\IH(ꧭAqle`+w<-wlQSoSI_FN"W;PŁ P/xUVAE>sFωDК# Q1a\dlxrO!"WbDKah f.oU,4ulW.qR9WTA%BJWQ=_|]LnEw˃aGhe_Ãw4 'N8zȃyTΝ.8dο52 16q0@H>Jٷ`2ygG>o(1~{kJ൮U;␶BX}(!t>I@"qeF7Vz2 y* od׶ 8jf_m_! 2!V|cm, - IsyU*<Sn!H-ү:sHOR'='تzvƴn#NwQL!-_:N!;)lRGftEjBHhD;f_,k\).rN@ͩ;cH,瓀(; ^l*f̈)3[p8_!zT XA7VfcTFPwE,t߱JELj<;Y= 2$Pl6mCm:.8X~|P`ZAB<1K߭$ŧ 9eoFI&\<&؂фs̩4g**n>fXĒK{Kg?>yZT4Ձ?J20g=E;4#::ե+%ziD"M[|ZߗLFZ4cq0.+N :Wa6vlY;MjwjLT[v q_f Q2  G44qK^ (cwQu٤Bu49(kcWH͘m]PFnVw ^){4{(  cknf:$8Mۤs @/HQ? ,f s,qXIS~6Fxo U[ŜIQHLjcyϖ@zD[GWipٹ%˲>Ea[#(գcB = Ewy|>zc"'X,v2vJv=Zu Tr 'P5'a r/H賱{O0l,`kA<:{:kBvb^r8fc5gn6cRrk`4cBZ9mzOo,EHTR3HhKA ~u85! z@.i4o;?Xӓj"H,}R?l7񜲸=qu`VNp=Z[-FDL鰚,մUhJ`f\e7=ol_HС"{?IZ^)~dasKf74p!!yNGVq,9J'TP7蕟5+6֏}tŧ3P$rGnapmb83Ԧ|k27-*,ľɴAm 'R'hAbf1_K瀎p3zsG*r>|3׳B8uigJn D@.7=+RCgm7h>HizhȖ)7_Q3^r1g5zY*{\,wBObH&.5;yF,Ƹ R_w`m_#ܐZ}'&N <xd)8S(U[l"u18vވ pv+}!{;r8(*9D/DTDudCE A=2W E6]l_uNfGcC?cWw52;Ш,9`F8E&5TqG݊2.Ŵ5J\h  ҰSSNPcWA/~YR|g5{B.ȌmuB>X[t9xN >Z◟VjV D*>S<5/W%oN*m*6 v3C功Hi=B>3qm"e ;dTrLac۞VaN,{ `[hzi?Ђ`> Tz<= - ᥱ%d,?c?a_ff̬8"0.jV7R h TGVW`W= ~Cp%(>)uϖNǘU -s'5gB|D̷[3aZi&En║ psHN؎覲B" 9 "+JY0ϕ'HT WDU#:Мt FWCzXZ^.r+}el?֨s7< TQY"Ueq;AW\i\[6ք:Z[퉦))q!.?Jn4SX03+ ȡOAͭBf1$WbU0sx4 z͟x%חC !v-cMIe&BncX_QeU9!a|i3Y8T~ʣt&$Us]m"+%487H"tL {%s41OBr+ʘecP[bCG &v\Q-ˈтU,!gr J|k}:r(K,z.Lȹ]@@"-.ˆ= `H~\,LQTܩ2ggR= M 2YDՎۭP q:uWP.r9e d=EA\(.z [ ^oo>eyB_"E;<3p q\\M/AnW@y/eJ ufOD/]4J2I-Dk-|>/EԵd\ E/`9˼uFp'd񎝸9gre0y'-(=i!5aI fyB')ČAA'BH>$zZ`T aOEy3;ÆOPƜ %ڃvAoYpð,nC vGXOA}j5o(Yja!4 ĒJ[ɱ.hnf"͈~H]5[^}(B!Mڐ Uǒ7u X1{;ĢŦ`k**QXE0e\k//} B M B_ J~δECL>9*QN`¸3'Z8^\\uRƆit-ŲZb%We3|<:+WY~'m~/m'CN)KASmΊ'Ocw#kdpcр4#އLhgʹS:6J[ze?!4q%V$4'ټh6O_) ] oSKg Ϙ)Uq"s 9Z8+SnOw8gڮ):pMz,$Oa`"_~_<%71.ʣ/g[Pk$YjXoymk/E&S+pޭeba#1hRS6I1ġyEKY^«JL蔶pQ*g>s`cK:Q%2Ϲ!Hg'AN-,v }R$m-ةDr IoysF_W'% 6c?_%ϣc< m?r%`5J'˔ZX>KUDRN d*6BD 9Tʺ"V˦:e쮂,qR(9~ytײ rz:4cLipT]na'7Bƭh pX+jƒi 0%L*0EJotL#<s/?+y<[z?8#sU~G(lՅãw:NhC!17I`ؚ舜i~o8&I@Rm澪xafzn>l:cL3c}$ SYыo~[GY?{6M_~ nr%Ȕt.lD٣3hMckג: 2+.; V@~%Yha$`޳^<>Ut?|񨻆Rh#cܩG?CmC|z֙ǯGkEB::ca"xsWu(.bUJ>Tٴ}{)3qBuS 9}żp`|ܨ.& AOZdt!lw2)w &L $1>̃/Z^QEV:.ϝ514Iv4%N#t2X J^I): K]~"$"b?`0D>- ްN>XbsGPx'Йdh&ɽÉzh-3Xgcꀢź,ލO:Z+qWaIԒZ-[F8s"lJXA@\F~VG#_1~2FN/> S1*4-؜[Mxܶz__lY@SDT}J&g}D1Vk&|nVN.i6`t#bPIGvj2,t_ \/žX8s߅nD"Tv'}Z~lm1a]ž쭾5*N7Kk(jN;Б۫1U8!Қ%<I*3k"~l gy#AHMPT!z訆ii@4;GBC׳11YoV6Z`/ׁ j1 >P]xKȶLg61 AZTxM弍<$h!2kun32h!MʇO{0U4 KYE"c[z2z8wr21Tis% lv;¯gP\Cx!>E1npULk6@oeOAEy"R ڔwSVV7Y#^kA| aߖ|j|;1K=^NYy_GKe*K "]c7삏'BM6co6{peW/;6^yPw")Ia_Dcr1*f9."4\47U q 3N@> רν @hqlryE甛9,EtN7Se~$ V<[T4a \:FYE!p\Z܍%X˾xdM-ﷻנ5.ϜQCY72g$vfj2Njr. v\RMr!x9)vbVVY/~ӀeK D֠8Z/FQ&؇hYi`og*Idm7ՀnFt`:!OCxq2nH8?@煣 #>YS˦bmZ~b%73ѿ2txRhWcԥa^1ڄ5C*5T[kĩɱ]`48r-X 6w-f2s5Qdj&0RXRu_G9xh4-'k; -0dT;Of;"# Qb79UWk2 P'$\"N_L1[n4)KN%8P`p=H,Бu = Y bÞ^W g7d3!΀d7L5whe^ӧٟ_8A| [3V=uKE=F#ܹneF2ꃐ•jo\D@m_iHB7s:7W^l:D\d%a^K>vkQfc?3 j6mx{L~^jf|_nZc~a:0A'j#"Pj b[ -ޱɮu@Z jvJ[lF1O% WO,%G%n`B+3tBo28}S!p&L 3Ho4c]4pKUj|XD!sT"1W̃9ytQS A 9o Ml`_Ӈd$<Ε/Z?IebݫZU۹z%)15"k~ޯ{IӺ' (+TB;Ov7 t5FNe)-9ىG)Nr5 =bb!R+JgfQ b"u?KeQޱ*gqr"-,ɯ槗q%A;,KtRW%>߈ng/D< kE^(M}}|gb Bۘ*K& gT؇S%nh)X;C;"G=IVMb)x:kcIgZw7dwY/١.MwK&8[cGGcZ@X>9]Qji?/Vqіh#9z-2L\E^1aҔ<4. &Iܥ8pԁ2"9`GY]h2DQ"6cٻr0X7y.cɹ?$xczOEPugMM{69%W]uV4RIZ񏨧.ꪇ|At-tl;h쫹ߥy%TiO7?ːFQ<ͮzhpV>AC5-.]A' o,7C0nq+`D/%\jJͮr6`쩀xhۖΤZzeOF}Ɩ4K_Yl{ct`PNܞt Jj~`ܧ)ٽ-&/zco%(Ⱦ&P C-[ʟ5 "Iym( >TKD.O-0<0u[ǹIYpߣK^/EK i59^EM_''~>*z@cbHYs,kz2ޢ1b}3.pTCtܙ?E?nV bZKfi[32Ah CMEk?DNH8Ќͅ}*CK5]d7@A8ȘP=oWj\Rm[1oY@57*GNPս֏Y}c tL4QZ`m˯k4,pc%~ &=rpl0sI07bHF|J4ē:m.Mbo`fA~ہ8O(eɃ .U!-JUc!#ÛIYt ]3bvuƀ@>A"JG?GA o|2S@DV |ٽ,rxњH0 fCwr-q-tr$c8ĜRe|nAţj/r * QmOg윅9LP5< w;Z'[tyLkfzGXW"T Br.õջH8# ;].5Y锌 wOy`hRWʣjmj_vnJ[vCO25YH I~_>KI}WqAMi2xWiu2Ի_Sv~ǭþ*1%GY,. 5DC|@ u>ŵPvOaʼ&}Rq܄Bq4`XަG~n8Cje8Dv"'-Gµ8I R ["P%Џ>݅ywlem!'&DåF^}C?oaɝ ܶ*:1{ _K`AbܱzE.d⥭ѻ{qD[E" sI(rO߳J6H+=*u"tUv Nya៷ʯ|#ynjԧ'u 1T"5Qr N-gQ:΃,A$r*/S¾T\隅dJ(1]aCnxb;1O?&NdAө1ve!QU甎g\-JtGHL JWqjjC SNjxBV狒^0 jo5Zϕ wiJgx6)Rxk^j}(aQ7K%ny'h Y?y6_M4KAz>t3∳puvsN]yMjo&xrsMNx]&qOs#IXl̋B}CbI3œ:ۋCEx_*Nc`tl]o@`Pz-9dUm'Ķ/'`fM %V4 돔$\^')K,[ILdZMm!-}fZq~4kU<޽2]LJFLoOkz+Cyw@BYxGFvӡ3/M|8H ]*u/|w',"&5)"+l ]DgwbdvѪ^,o\j]mmYԋ4-po9`RQ9vv[]ዣ>S4?/rۂ%B8Q4>+딃tˠc>$Ὡ-zL9h@Uu~ۅ[\6+66O7Ս(Y gt ;zŽrµˋƘi,@_ʀOqS ROQ)-hk`C$  to̝Vb LeG c?nC /,AY]O1W"I} QĒ|+Wi15ӾWK6۩%9w|LMQ;ƕéJ*oSԅAVmb~pp xwY_`'&"y'9NfULb +`<1/D({|D0CGEIYo[29@b?Y S=`?i0^ؾ"/>ۊ(Ŕ37uz)'Fp#L§d3i[ˋ̇ScyH), FE;9>yߴTx%ȂO G ]kvwk+n0B#Y{kN$b'q& Ch\1T^oq,ɊML $@r:v] r~=؂.=qŷ+m1py<}W!{xcCSz/La]w^^f8R@@s;.fTiQv> ;|Kr|Q^9_=* ]^Iɿ$ȓ9J:yoe gB 9%pIT9_}`K3'IqMEXo/)3&[$+7({].߹rF_GumDi,èu׾tu~L$,y2 {9j ]Tҗ90@ҡzrMIe[X$62!_HP.Vcq5kµQg0 v6Iu1ۊ6YO<&9?L*ć7dݍFic1ئTQXǃ3eęsdKTKCt{W'nyem\Res$gP CR)lBo+nyq6slF6qTcZ\%^x.oѿya;i"@}PTa#C׋)+i(ϟڒ:ՠ\UT8Fp`덍N;yIIc(:譔S.9yL5&3[Pj/nVF;M}y̧-t̟ U]DA3SzʐWHÚpAآ3]7ٺ6A'W`ر>Ƃﰤ#<7bG^ ž[HH6 l$,פ/H;CK w4MU,OA7/=j!BA|.EB# >$.^rlg 6M+4DX^b=WnIqS\qh&x7Ea)1(!oWv|2-ʈ4gp g!#r+14 rЦPh8r)~5h~ymWcWac TCTe[w/ک<8Jx8@A ]Mk|=LT9.Q>0,aHJXqSHQ=AǕUx0B  EHJ(&X'u:bA=8vx݀(-Tb nKm*@{׮S ]J 9oD䯶Uc^cQ~3f\bDQ+ x? ȱϩ+"uc5;g$V|rݮ<1> QWSȌ.'7w|k˽doCuK5 B+3{wix- ϋXDrn sp9Oos]^a*'hmL@QC Ţ0UT8ߖޅ+ 60iwgxҾd4v|R;2ݳr[*K"<W [f=kq%Tbr~] 0,#&icuh\rϼfs\oۑE.b툀: I@~?'B;6a/![yw@?0FKeWT0GL (dHF*/{<8/4A/1 ,H%xe*Ś%zefq9@I`X?`VYl1lP`ꎗ`~gѪO^7)LfAA224h;_1XL{ 84d/~*$$$zdtb? Tk(x MZ{PC&{Wa~WgR _KC Cjǎq/kK2Za2]=/"y0UȂc?kfEAQQ kQpmf\D-q1r0&EJ֐cbd&:|,O":&}xcPҳo+@pVJ?#||ZTVV%:'nmҐRˬŠ<Aǟ+ OgPҬMLn>EpS/y[[a;-Q[>Y5QiQQe7\;a-mJ9B=Hʘ pˀ50pAA-a7e?{MvJRrC68i(M8á-A.=hkZeUE->l<*:lϾr/xɭ'$^pQagqעl_ÂaMwDQ2_ATN4E҉FlPTO|5f3 s8v`&x[۩ė=z3ddY>vtxU鸱 gm}+B \D%9<,_N!m/QsPn~rp+OĈ}X+ qdt+{n}o'`[0%{9ġ+to0Iqo't@!t$i R QX4O=&s]nxt|%:|0K^E~%Grp>W%JДB ߖ2RlDa]^s4[›x qSp i-<}RfpDX-!f M%ȍ0; el7kVw;Tg< MO#Τ yHHV$C/^Yeoo} @Z&=<̛W{)G9? u"`d|vŧ┛ <f,ȷ0*u)BͶ靨#и7T[ƇLǘYBhٚ 9l%%YeWDX Slv$EP9hk)N[6Z|ɠn nQ*a#plυ;qi.M?@5`+Hc&|5A&<*-"駊#: ~ffQ`̑h)5^B@Gߝhz 6E{sLjεb-CE$LV4(kǒKSs]-x~8͙&'  On;:g6Him\e>az͎t 8r[Ӹt%KJ )5H_CH9knE8.IᕐҢ Xr]1 im[{?\CCf0J^WcL7iXt߄F((R'\KTlsP3N`v7BHͪpbX& {${=҃GZ6 5mv\z^Vo<7ϖNW15;tndC|فddAz+~0a6|rw)T.:RJA_~k!.)rxȴ4qf'MTxF8yfHd"ײJ(ulڛLVɊ#XRI0&ߨmS#oBc$r*7TubRm"tI{keHTGŎЂf;R;n\+w1$!U}Si>j.9uG7"uzͧpg*c{2J.GB-圀=`+fy"llD!f1G3NU{%Ga[h% S68Ɛ'`xRaKh]0 mz >"5|7P$ܒAy<7+v|(Sr xBVP7J|-KL°pUO<41=2&DE%(:ImJPa /-On&i-k uY{z M9>wdslzo/:.'DfY[O}&98MQ_92Zam c<[Z/!oAzA-Шv7jЅoCVB{G!fnIMSeDM;&FUKR}|Uo,q撀j Q`M~x%lӣ9&R(c.H˧L{@H0S5nUTUWeؖSqf7^LIV,k ͑OGV!qpWRmgt,NTx+9dR0(Ho[yܝoZe ;cA43_`\9gBEc2S j>f}0r8Gr:ZE%3f߼u4'@&, B (+VIM}ʮp()/ߣHmFHw& o[憨ZhhWR%iiIҍGeZFxZ{ }_|v3)I+ߟE߼٩vs#/;)N6;8Q(<`rQ|#[p}[V.W -y V.,qܧq RITe5r2eR)%slF>=RhF $΅|FWf1 tk?Rڛt*;?F_.$fẠ>yˌT) W–js+p%4uO ^vm-)sV@7ܚWҀ4h )'*VJyV4M4}4{^Z~jf54VxDiF\$}c幷r)K1F xMxJ~ K<يFI,Č\/pT964Ly%E%>ϟ<ނf *1Q+I46M1QcR61{rv}.4:GJZ ,t?$}sKy9$jE׏˵۸ L_qilҍCU1r[ɿG#¬ƾΊ<e ~aD!t6@֦8@|H)g#4Lyr)iAMhKRlWΧgڛ>UD<ܾ$} 1SQ?ɣg r ǁE̠P.Us*N j"UNkwx$d3>y^.Gޜ*фseCrn+vB.K  Z -^8AYn0Bk8$GyX̿jHsD hY({\!Vy&V2đLm~y\#-mNH9!8m3Y 6Udj  GCqӍ°g1Ah6o1ҡL03jgWzFџ6 Ո{l|!Pzq}YHƢqZ[-'ʊ A-2,]U)ߌpo/g[RB*󁽺ccܠ?C5Qw<}Ց7+6v Cu%o*ha K Jh2Ҳtq܎}_'\U9U죽h0 LTo{uǼ$ae;ۇZg At?.-y*+$T֡p48ܝ~,1p$ʗ5? ^XR0 fDE/ofy<Ń"7X5 m{bwO2  G[y|sNx`mdd:U&Ӄ Q`I`* j->ĭ҅B00x:89_N)&)*ADuU7XH͹D,{MQs|q 'ͽ8[ER?8NJe% m{SZ>^ZOTXr#Hf=:BdR)HSc%wv:ѽl0.yc{,θR mz , E|lOm-f ~;wx®c;͇^ 32Hγ/q*=ҿNċdBYV'ֱJS5'ӂEv@M-ϲB"^BE#ؖS!Q 6tdTZlb!е{N#@& I UA6w\9\Y6Me_J,~dIłЁQܺ16F2Է@|`mjVPFUL0Q6t(_Dkf)޾EFњQW)O`4;<ş%&nͼmP$SX־ BFm+5y'ߢR&Ji{QNΒ1,YnhF=p|ӗJOD=?e݀S8c,xr8q"dVG;:6c w߆si>~ŋAc(uBD $i4{R;9T}+[,KMLt+,*vW<]?UT{NH D ]CZ'(P"ܢuGT`!OܤJ)\fOU0%mJ\ C>S .i@Ⱂu.,6Uܰם=$euFudl,{3xf fM1=o䳦bg)ڭ6N |PBaN|8}kS@tK^9sHQ=0:jF?;4H;XGr"',ݩ޽X&%:Na=TAt ؝g$DF0.#vB>IlZ.ay߼L+{t{RNpN侰>B}BM7m+pjU /OT ZrU`?W4%oe&uV?.:g,imVAnYoH\a?UeۃDTg6eDni"4qo<e]BBgz274jVoM5c& CqѴ0o_2/ 9 Қu]]|a} DSG*ڌzFfk9C3Qʊ&~•F2AD@(jU#rҧH*22څq@{|6E'$ґ=Qԛ'E!FRS4e6F| pMJ|F'۹X 斋@d{,_ OхlkxQLIO2:0?fiW {'ۻ` ת\dz u0܉Ը).M|AL{/01cqqTi{WŲVqlu;)6H9ɋ"XH'b|c9yGv;?P^/1ZA@( ,[Ke C,=dzRNsz. .+I>0N0\54;S;asO}2mF(r7CkbH%lE~K󐎨bΰ fY3wg?Дo4)h3n3nfD:]Fm_ Ϭ02ĉGv''c'7`S*N`HH, K_Ly~`=8 a-6 Q/} RW%6-j#JY=NmA4JkG$>b#޴x{-WˁcR NE#;j@9v%:]5z)]]E\ҲQw`,C\vn{ޛj|Pbf0,0j _;Ĵd€AK sWh͖@,䫭FG>g49yݠiʙ-&Viyr"BdQ:nEEX0S6BkP&:T>O,!T+/cQ : tfpM2,a0Lx˷pF #o7G'HR2NAIGYgOMY)>`E6+My@/p`BC =֛YzC ?&" EES#G˞TEn0qvzX} ,wc\Pߛ`b5Ց=b!'7f PY3ʊ|kx oH~B} ܩbL9@`-fŶe7QNa!|gpn;Gꔽ<`qjKiĈ&Y|Qx.gYLA&ơU!G*qk2 waB(Z"nuNknHK])4?5#U]6yɸe >GqcWGNG>(h}3LͲ jUޜ, ي`3oE 0--m{A6Ӥczl#Tlw򜃐)ٴ*)pzbay⯥O02OKC< !% 姴Ǣb3vjJ!ـ]@ҼWH%0Hσe:`7o!eq +fc/ 9`V:YqEcmV[D#|\`@{ K%-v|#˲ڃARB!sM=AZLX'͹P<oQȮǯvw-A:o:QQ(c@].f[{ 7wpINS2+.sЮs,Cz:٭"yNyq}oܕ5u6)ZJK\(~;8Iܐ]~'>ȝ_{HB`{仭3`#}OAaw$7";)3]ʣbTm[ 4Ʒ ԵnfwGEe|)6B]z n>%<PIRn9-(Ԟ| <4g;3oP[HI/nJQȪ)ՠ .鏾;( &+Gk;9M’5X~mM cH-/俜I N "͔XLgLD<#^ 0d.($/T6aEX=\ |'%0-fTz`}*+sݩ]B2t0t}dB<=3)N6E){a喆K\]s"c ;Bq@dz)@NS:ůnJJt-ڝ Ϳ?SxQO̱7:u]l}IQhzE@Mhs^(R]8\L-BJ5e:tV뀙(o=y=|rДeF$s3Hj(<=ILµ5mxF HX@J̰-k%@ؼ~3?2yJ3xPHdC.(V߸n Kafy k.A-htfIM 9~UxqsZ J + "{5_YK tHӌ Z(~[T{)z{(֗lȓܜ{8!&B#6lNTB"'\HҏvE&ATX (nFum"tgZ\AЫ̂ #C:Zx=#|''v~+}SfX.' 8j+|Bc?Þ%Xi8 RzղD4X/gDxbz{4Ur'lǜ}3j]mmA5 yon2ꩣ]%k? ڿ0|%Vez\iEwmFԡ@5]O;xt)nj|[ٔ283dVS89? ?}dU4GA:s"T9l5r{Ȝ⼂h%eEWPD"#/0H0`(7%d?`ʎp:*h;R<zHKqM7e7@$bCUX+j=nso ,:do(t]@dy?^⍾qYf%ңJÉHk$X*"CJз>+w]c+>t[6[Gkۜg"݁MYPv^ВrDX iG5r 5Ă7+Kؼm/Ũ4*KQ_hYzB7WgWup ۘ Lެde?{a^[2+yz\|/۲֛GXJic .X9#`[&weX昸}^~!<\W@ؒQL}[F3]Yg;m:<ϖ1oPe#OJ@܎\ߠ7[wr^' H[<#쾣k:l䈬ܗ]0+j yS2 Lą==礌 TME6 mZ';j>խP)Y; Kg'29z1( _K9pϠB_U~MqpL 24M8{K-`wXFٜD1Jj @\ e4/d\36vMo%9|>eze}xp`GUKRf|dQKm-nU/uyf&n  X: Ҥ倲XO4V$RZYR;&[ZJlRW]#Y:Wr)6}PuSW9'Fv2C;-JPiͱN ȟ8q݈T2()ZVޒfy23X*'2nC7DkU.m:E{:\j\N@e6hIhp;JQnhO/9-%h^dW, j^嵽Ni2,O+M$g!&[E@W ƿTlCYpKNUQjXaũuKi w){:ddG rR2L#i/ږe&59.+1 g@H:h9OwrТkw"I ^ؠco-Fm&F2(LXl/֎= bd ŸEu,4 S6؜WVEB' ,1Ů/w<"ÖQI 9">^kދMF2Zh£R7 qL&7-@imu (f(ʡ!w<ˍ?Ÿ]۝ f2,;_\*rK*zt݈խ #qӫt&,^d6Ed,~G (+GBn J`9_u|Pz2QěJ*+V/) 6k"]i%)M,o,O\`Ẇ8~CoP@].^fl<T92:bDBڎ Hu Z҉ћɱyK 0^H!Sbj?9cI&0 @!R{q41=M~!?L 4o?u u:a拥~ftLN,g&HxxokЖ1|C[_ZK9R [3Xqȏf?uo,ܺríqs=6\- ן=fᚲxFx4QNה@^A'V $TwɉukROSFuym2FIstV^eA )S+ 1C FIn$7J? b쒫\bF2@MS^@UDj? ]ctSѶF]Zz #v^o5ނ/$MіHkXq{wJ^{`" <^}&be4Dn¶߿N`'ڻ_. \Bc)?,0heb(f; XFT/Mcfė% `ІvPy%rP3SaR1ҕ:ӻx?@=UDnQiN6Z ZI׊&ݙ?Su,:rhoΝtk9H4ĝ@ᮓ <+iCq.OsI94ָ?1_[%^FT*31&cR ww=OVA,q`4/'7`.P d@4pU6>Eˁ4=/x3.+R&VxrAq!^kZ'pv~೼r* "WϮJ}| Ǎc ;0/ං2:[jF=ݎaF ?-`E\qZta< lj006 DnjMŔ!GɻMqä?uM>;Sw8-9ˁ>weMpB0WQ7Iߒ_/DcэhT _75lfQy1+K%=Qs#-c$U0W3Uxs VX|f+.=<(]0?6R-'!l<@@!BP#㳄6GҊb4$}A?Rxen|CE}+t\ mk Y'|cbJqb#d'y@3ܐhS+U潼Uk&Eo Y2a҅ "ȂA'z(ȑ-;DJQWúio|Tyy=)Je#2рN>g$V<a.\V9_n[ec6)Q/bIƬ2 /x X Ci'Z]y;j|QCsT=]bHeg. w^yq*!Ee6OwK| w\C*ٮH_BxڭT \^+)âQ^/sr=eJbq֮_—`8gCW #ޣJ 9_|% l$PS] "_H?)q ]N(BD~K>Jb&i3t7-{+,^p'5]MevrV76$x{"؍Z+㏚,P ʿ}& u!"Ey+o(ϥDRr;Q,CF'ˢ4c s9UP/EԦ(ڪ妻$gS]T$ҋq@͖)v͂CD<͠}qlDb!\ZC"/ un*zG}N\AXЬ3 "W絊uQK֪[lE"ri}h'bG@"i˭Xe+A: jGw_jJ78$DfQ;Wx5PG6ܵt7?ene4lLH؇蜆*j$7B1>^*;xr͖'Ǔ j 1M IUa2"I]gPQKLRR,$=&8= }ߗd&ٵޟ:a7 䅾/wıT%40~劗F0%*ho[xFioN\ g88Sg')m!abad6n9iJk'MipD1dx&7דZ>;#t6|Nd65d' jsaW8n‹E\Hgǎr~/zzt$XC|&JfUВ=_|gDǂ ÐQ2c>UHAf>o6kkl|6{R^[8.;k)V2ds#I5z 1h-~Nn: jyT|C'$'[BG߇aM4FX}nثW eSJhr5CB Rּ+Vq |fo!+?7_X4vk{5r2w! <>&uHZe0ozROwBAx^ź ms tm UPT{"E۠Ce&7M\PKzR1֒'.R'1$d`5t'dr,=U\gqt}V1% 2+oչ՚6x:J+K/o A+V=co-ZO͏I衂 5#"~['Z|",Hov)ꙕ g'"#^v W0 /$^}0,뙽{ GSW:*y6;!c( 9TPaoU<#)ڔm40eʖckYiF@(c&4;2hJX|7y\EuG&Sh&h?4.q{tY"mIIkJ!V]↦n'2sIqo.$J@4 0$r|h :?z~ MA2^WYhKwnT@&o'Fp*mVXą!Q]]^CHb0K 5ž@I x習ٯXD‘질j4#Ίpm?}ܷ47h3r^zH̗*Yos2 qf'/ͨf)ZLފ '̍\Ӫ"OߩqʽR1PDz}Yz,^c A]M~L 8x~dmFHnF@pY%jnլ@*t>cV}d1RSoOGj jL'> ?Ah{3S=hwI?A/SRnՕJ3U,ΨJn'2hgj)De8ĺgG}lcK2@zj o],S}Y_9dM6Ä%I{ M`l=-ˮFsm"ŭ,"iSp\ECd`&u5O Q y::1Bh{6[êb3Y~qx+?,B`z$<ť5 𹲂ëeEr?50bkY1=o6o%2(jCOU܆Q`CW5wш\bղh>$W›dΝēQGoiQblVg3DxnZ{ 4Zsї =F>rtRYA$@R[4뙷7߉j "k^YiP" 7w:+4H<Y핇$ו6j$صl'µEZ vS"Zl#[.?!;"b UBm;y: gqlEb`_DlU.̒|E + uD# hbxzjtPҚ>YDZang{$_nLY1 >_sV]Uf{[ Վ=*v>rl4VB1{DL?oKP,)SL1)vD^N )?us 6k!KRU"7s|jiJ-EY͕_lTS_D7J} Do>v AO^.-. H"ANRfqTWYD TȀ?9#,hjSy3,p?YZym9R#~by}$nE=G*2C%4֝7k)O&] %kާhdJ &'STt14h zFݣ3j!oV5?:Z?&tfAB).H b2*j)ڰi52 jk}{KY7XxސZ_pyY.)n1A.?$*?PMZO.zzzɕ*}֠Ht7=eLdQg kFe lBX/\;F!cn&b #@@QaɃIbTNIiy**/]DRE-ۺ0C+FFGt T<̽Πk>|,}] ӌ6RITLa_lmd"B,WŊkkU O4l9=_wb.W `]t ($2f$ ~NMoo {CA4%;ᕒ} 6myNì4q<JB65Dr0rۘXNt{srI [wΗr~ɂ>'!\ҿS0#m8`r 5RRdfcՊkpHRʦb1 =]#O8N^#s}ւ1fvϧf #T"#nX&HQay%V5e׼~J7M7N.b庾/ =I+JwOC{d(yWzĿQzmʵ!L8_MZM>M1c*f%j+ |rLh0>F?*utO-}v72 A5k2\@eKS!T9fYӲ{`u.Sc\hE\,jޘx7n1ꁯ yx /W9xu+lraבЊD9s ~zr*`L죸E%+i\ue"Qa27qX&d *ůծO;:NFx'_q9B!ZczM̃1Z?nƙK@˘ԋ~Zǖ5",BlOo 2cɓqӦZ?SȡmcuR#c_vSCPfRgQվh4\Wp`X; Kl0goppin ՙ~HˣeU yh[m;)#^۬Lx8|XX3R&A#j ~ 3k4@ *.3˚Ïv#wd7nB@9.T@/#Zo:4K)MDG᧒!|GsKeUba1c_Bb%ZgMߡ7A1@𯼅woi#pɁSJhorP/KTaN.[ڣV-}; Cx[@FltIDtqaJR:wGBc;N`c!ЎFUþlGˡ]wC̒k‘TZX$HD֕S1CJ3&ZHK(y0+;FWE%J0#GW'5Z'8D11H,wf#C$V=$EpMs[|=KJW0CIP5G \\8HRNh׳Q"Mt7gc!WV|ɔ~O˸OQ9=Rfd欬@Sm]M/z6VR*4 *魾SNq% &J\p\Pv5s2̖,9x|2O}C 0eVBY#LO,kG #Eu6 QJfIE SYl9廑5 |w=&D%oGzBCZup sKq!CZI*񂑇W%=ݱpʚUF[gq6Y%hWiܦq =~UKA'U/ZܭqQ*ZIӪ)./FI \ΫBKF i)ӬC~fum&8ͥ/*MR4)!\gj n!=mby u41e,W:)!ӊl8rտQWڕcK<3p~U[B9}p & qZ%C;>k]dXlӦF$>PW Y3g8  -{c@E  QX-8sA=3{,*ARH3lUG=X4jGK 6IwI)C.\Oo ݺrO`g:1=o B80݋Q9~ ϼ,I#?Qz {Q%0!X=M4_`\q^#݇ZdY$[q8!]+>$"/_͒jD*̓M/Ib&v#vJ-(wY죩.<]]Y(!j4Ҫ֠ 2&kxҳ5)cFDnh(#|@,^چ1WQ& s vO,0:<~K;9vpF7bI҆{ ռ}[^5O^^\, 1p6qHHQM5y 'a? qZp,߯U0DJ4ɫxI/2ny7dwm5 _nu|G9'rh럦ow59]WudnNUw#D; 8 T.#e=rYў MEsKkzzdSkK9ӊygxό;ȜѫG om N#;c8[Y'&IV lʮX+og]iXR9,OQ{ᣋT/Ӡ w U{4Aa0'#=Km6,fC^K:T#>XF>}ѷz'X z6lFSW'o_i%Q}~F/o c6=xfY.^[I8jR)'ɨ;, ^)Hk^*D'iKwkpVߊZ DLۻfHG,K$EN|Y\WH {(T?#x8G+^R?$`!ľŋY#د9bm\5mWeG䢔I 6=/v?`b,/Ѣ|.%~u!߄2QQx oH']~2 !2,l輵|Y(L9zZ$2gXȖC/WIRLuӢ 1h0I `7ykldyC:L`ܯ2-'P tYXaEbڅbtcJ;AZȺ{7 X.DPةnhĉ]}#N%Z?<FJ|gѳ'Y^m-mDih>Œ.v{hi'h^mJ lh1Go`h2+iVrRiZ%2jG|d)aAQ'o~u ZADGX sG=򿩕񇩵 }ty 3tFA7_{^z)M'%$yݬ7Ms=* qTɳQ ^ҭ̟ tWc)UeD;/sV%ܗ v<@,?.J@JK۱H ~&'뵔@[3>g@׼P%v6rZ#d`~)O0k 8W%IOΛ^ЙJ7`WX#1⮘QOMV6gtxCk 5߳D}[MJ+qxܠ`a)Iz^ qBA ĸ]"Jk;c'g]_"Wq`\/֝2~bڰN'*DUNrGKW$m uHDr# e4epHbJ^k@)m]4 5Եa9eB'sf*:(N< *d¼ ZCc!#mv-r"_o0PmcB p^}66wJ*}ix=|^\ۅ!΍H}dNuTfmKiKL{(XjphܜS905 NH2!/!?11nk`ʂC& 5 B|}e`JvOpEz BVm@}6p_?YT272h X!D` pk/鬓CnUÝ )6(+QߘV\xeYcf(eH$ZQr>CCZo<{􌓶@jQ*wg_]vR%-.s==ʚ7`ּaN\01S܁$.^Pt1#=-"A㽻'MVbǯ4Ht%mibx\\ Oy(z%Ʌ ?yVd֫Xu2*]WEie1E͞ &T̏f 2̃69#-FJƴ0yxLMNvfroAڡϣeE(Vc< ͯG攩QPO#_U[ᣳ;˸:1S," RFrjb)J$dB`Xmp2.vp[{{/Q?La'k('dXjM;rݕWc|BF )/̚$,Y8gҮ qz'g,O}5=u};C^L`1V0_40`=xpBu#jWU x_`-%+U< DÒvx5 *H[e0tl@߳duֽ(rkАj]p5VS- YB\7PEWh:e=/U`bJ*̴ 5F\sP⛁qoE >[`C->qIr3b|U|;1Q5Ey|ԏP*Rm_03Dͺ܀Db4JҊ" #'K @_gL"wGJU-|qSCNXWɣ%@q4@Cn m+\BNN'RlP$?q:4g+ytѶ{Gxi;e+,04+u,@zE5fwNҦ@ܝ[I>:s ~+ Ŗ== [R7JMfRM)o>*q\3v.\` 3v?}5Q mxߏNbJ?F M\ǑjxF.jDP\,k[Qb3i %e`3Y9]&:gnvhg%R҄#PoC's";7q>0]} H1cD宊.'Js__< ʋ ɴP*_L6*{XC6[{tBX;AJif7W]r2s̳at sTsar,VNT)*.}k)k4ݞ$fkqx-DgEP3ׁ* Zn4|s3rYalEw8mj=F jحo* oh_xx c3˃XvzƽElcTc֕!q-mc~h>k\~Ǖs%pBVA_ET.ʂ c+Skȳlk*6g|dO::p[r5"PHg§~sݾ= ZGl{fF)azm>H-1 SV-'1>IY΃ߒ uPMtR*Zyl?DNi_hΥ J{ȩ3@(rq7ZW҂OO)=5;"'t5lEKnEa}(h+۔\PjgiU- ^t'[ެ,iS5Da:}.\\} ?掇&iu9񤍛|C7ܥXNmHhW<|'ٔ:Nb;=>߿vyo~PIR艭uooqm ]Re0 C&0-g(-(5@X (6>elNs3Nè}A sͳ[W5 zcw>{-j*)H@7>!v(Os=DT1cJ-C6C4pab1wj(e:>{t7絊 cN޵r&4R {/f1(y#r[JLQ5f_x}맟puE|*q;,=_펳z[EDa4TU:sA}J >\ x63H|,#Y,/l9zbf}Z"y{N+oD~RHV(T7MĴh%uygf+N"t\re.LۣR,x,$ rιڅї1ןdbud 6Eі ∙O _Ð81`s~zٰv'VRr6TM!Zf]3 2Zq ~VJ;tlGi~#Sτ /iu߆Lԏ]JůJB@0gM{Cz3<]E"Ѩսậxdx!Oo4|4YU 23w!^AwvgoӳgNGlioʉo,bsNX;%!$Mjg湕KπnVD́QdJbg]aG9 B=2 7TQjo5'v:k}7O8KJTQtظRBg?.n7!3?t? )7[Tt~ vf贚C S|N{o`ogF9ۍ.̃{bv:>m1hnsYֹ>˵GeԣK*+JUpTQ$/4hr (J]kyO\iHt]z޵eÿ(Ϻ|Zy?va~qAZ&&qJpbpVj+-!.XL2`+%Ž[e\vy) Gkdbp,y sM?LU!}B<~4_ )g1l iN#Rp^\A:cў尟kcxbPkݵQ9F1+kܧ;( u>⨆n`W'\X:WZ40s9Ӱ 3?t8XrM"7+57$NBp^Yzlw?Mn\~ߧY f:' =EPɊجri3L*0:#h+8}$zҸg.Uߦѷncj|c7OY?U͑ߵR:W5;pƿLb7S5$(^52aPȺ$;H_SqOTX-N; 1J/Fjtzy1՚Gmjec5"a "PKYJ364o {ۻMv*om圾zGȻ큅cgO\!\y;H'빨-ҋ_y3 W̅)mܺԷ%Ή:_+)C?A_`snpJ ]rr=,vFqxf aln'[ Qw"":'lVWBx21l-s9q=sZp0%f! 8%= ^Ǥvz: j舙1?Sta(e ]`^ (R]C}iV,*'L:}yx՜+3pv&5e*`t_T) ph|h{ǐǑfJݏN[pK+Ċjy-f.-F{t}]Ճ/g%T,I,.ֺ gSBG"!uJC_! (/\fsFۆHo]j ,"jP:{#;p'A}hU0:@ilGۜM[K"슀3yϡaql.8N^,"Ж9)(8d{ EGHip{vtpEZ<GEP>Ky7Li[CKn##gg%{ m|f(,/? >X ;ᗌ&ކbxH, @d+W"VB+䪲ĩ{Q‡ں֝g=7pmH+ h"Bv*Bj~M0}&7>uMk9f3 X)RʋQa(d%4ę5uѫ@l%;FoǻFG<|J壶]do'l# qZ1uZUѤ<R+O cYG|f):n;y)$idgNAúk]w:{ȕN9& : ]U.Y-G5l@K,}–TPnގmu&' gj>T)[2M]Am639ln/Th<ӱC;[_͜NlnWEI'UߜeCbض߂8+@^RcqX`iŜ{a{Xӓh}!ɜMa4JLv'x@LUBtc}}><(P㓴f̖Q;k@ALPDUX:ِw#k]1"3Or\ 4fr6tN}ڝ4pToOygKfr)Pc#]|D _]ȖҲ?xс +='Ρ;Ywf䌶)ci4DVWj뷮pd63%יh7х 2w meg,4Ɛ8v7a'z`}Q{.{o{=C37h=ug ޫ+ "y9B=>0:%m4k18N<{ɿl2 &ft~uu׼oۿ侗$UCl )>1NTsj,r`ur$SR=`vpm3zP 2E05'"ֶd>صNn^OrN<WcY/A0ppw+ }cOb ܑ?ra\)ZJrlX2dmИ'IQ)DR`2;?Dz $a׋-g#^yv_)up~Ê,%C xS@2N&t*@HƁƨpTCN4$' 9dd$%@IW++Tt$l[m׊(Z4@Ӕ-box4mȘY<ZVJ$ۖ i{>caK)`^7a[xu$*숽t"a-6ڜӠ@Kᲆ [ï{m{Kú>uӤҜ)]p)4.k{IKjCP3&&x&@:Iq\.񑾓o?:C[#®%):H敓T LB8gZ&oQC C[_g>6M[RZ[c0s}Nmcә| <+;7MAi_T$R@}U2Gғpu"hgb28hQt7ŸM~fWPJE:y^L2lϮgѾA<5gڴ(2S,E˧X 崛K$HTm}٠.w1|Cm^"Cצ&aI5&XۓnL3h 8JUhTjq|z5v]69h_a0қYԊؚ[ibO9>k-xRz9}N @j^X˂cbgZ=7D8*rh5"?XZ,W{K5?Wd`Έ7, iH;Z-EH@8b?YzҽPB%3gl\b]^hEPnwELsȤؽ}e{pMע3kg8//Us*J+7.lQ3,Di%yiȜ|  ȩ9٥u>,*ߋ'xW ln]s5*sZje.tx5Ц cC.2O>kܺXuZm:E߯ԴX\xm5D29c/5/<mSB::PxXlcB$&A2+v$u1d.h [ feak5D+heѶ/"ΪQ"4ن\Xr ջ8{P\M$S$ VSHǫOK5JpMs;#Za]~ޘ\{#Q zFvP:tb-˭1a08,s V-wМCscp1vVHH}zwibP- _}vݗ5hSgJ ۑzѡbzB?N!ߢ,b4}jWr:{FW=Ouø̩K1 )cMpY-*NƦ7ۍsELtrə+ڇ;39~Q6 ȲU#fG4k$aw2av,1~[JD/ipʣ:gh6_x !'uI޿V0AZz.o LRG6'[cxP]^I%S \+ h6V8MW o9BWVҩ`8h_g!%DH@c8w#i5Y1K m8c84{? &HůŞC 2P>csfR4Fl߻s'P S۽_ ?ܖ"x~0לRF0<h@Pp)O=*Is{GܟrI@[sg#rtGen_PNͅW9˷" X`>BI ?%^ъ9,w;3U~&0\ y*l~=s F\,tnQUì3ؽ;)+߹ʒսXay"Z5ەL//ևYr H*pU$#lw+`0/Ze \#lvKn}Z }Ɖo6LID|(fzAgO\Č7і4CF dw+YsCI޺ |5(W$C`fAGPGMGf~ۗ墴/wr8P@S`s',j S-mfWw.ZЌu,Oo8IɊ a 53m'0ϕ*\}s='aڟ-r@P ~ӓXTfͲ_@G#c4zRͤ"XP@\[!ϖ7!B=p2"T%e$rf/E/Hu-?{!5TVĝ,O-_:#X=It0 M+ L@i[1宎+<Æ{I LfDllB|һ Ͻ:7?L1-̴+kmfqQDQB#MP9\z_Ld `1\  U{B4AGc>OKt#t>dl'4ӲM@.tk J "?ŤY*;ʺ9\>h!@9(a4C뽴G'R#_OY U]yt}U Jr[xRw^9 GR0? k7!T(|g۷x2U B.ŷݝAve,WjG\٬'@+0uֲisI*ndΏH7?fd=ݧ֝-zPke2,Rq"Fr)pt4?W{?~0YÜ=׀TƑ#¤8|uNc3b&⒑Yn0D a|IMkU!M.r>շ3$wǔZnWgIӂF cƂTDNON14jV^$:mbL߬Nrf1q'VH[$ V `3R 39FцHp;O:ghcPtĵv )A[ 4zx) ie212b,ch︕cE>@@)J/?wv_:^VK( 6G9LK'Gs衣qSC[z U3񎘯闽%DL$R# u,N v_9<+ź "0GyCܵndO5v=lOCc}Q:Y^^Q\*(֩Ӫ} dA'5a}S3iBvsCiaSEJUL(4MW(qDMTn]ř%y8VO*Ӄ}428B:Q2s>!Taho=ZG(jhud/J]31j0>s_izJƅh #iF^q jBǍ20Ve`F]DC?G{>Jg>E%]ktM!.j|Һ+Ţ:X3YJ6JnJ.}`Urn4+̥2#[:Ȳ_ɭ kPhn357ۃ5_>jN@Op8ֲ GWyx@+݀Lq!*v&>ARwM >ZUc8;\_^]6onQ#Ŏ%j:<.Y*jd;?(l%rM~6VgwUߏ%z–:zV`_ Img%%FF-~qx?ӹTWSJ>V7'gBREտa;a^KT [?7sc/̟̓qy`ya2Ġ%Fla*z0׷0qG>['6T+CcOyN " eqm =fO# hjš>^t+6L#Ѡ\u[,DȢ\ݬJ'Bޝ&ܪofb[E\~^LΕr7&[53tڎr+34cgtu^9plu*obIݐ*DG~C5j2gTU>HӚQBFYsH9&Rd "U3\1_$Swd[P`#X/Qp #lCWk(']؈vQg).|1ȑ tkKS,`,h;*KMg .K*+* JKo/U8hXCA{sfE`W-'?!QΟg27= @9E ׭.@-+9nJ!-(Ϝ>ږ"Ǫk~HS;,-יD#.eRnXalh<<-0P-&[,0asUBm[9'l3O7M5UC_CU:cr1s6 v M"&31@p\-@" ?ށlI=*HX#[_r1Y] +'n&Q HKϕK>sQ*gLǃľ0;{4j \448q%to|hzK,nќ1竱g=#$~Yz'dad\̂&rtt@.7ٓypmȈjȆ!MfԗV#Ks)KBz̥;#@XyxjO8ա3hWY5^u1D#P[lZ8<~ȗV jf/X*Bv Y6"x ?ܭF[ }xjiޑo]H%e="kRT0ppb~b8vg'(4_L FD񕾓?Թ8rpBL:p֕Y%TR!t,Bl#u}$Vz0?W6{d 0slX[3waSIʝ+4,w=ϝquKA{VA~W{ܡ*Kmdt08S0fj?:Iy0_uNJQ1Ki(wN::BN6a!&gzgכ(UxZ$-st|y=I5o:> gIVCI4AvUoZ8W0Cm%Yt LwǠ@ p(!ESJIx P))̠JX,S'µ[吶U踢Ԉo]W̉ԑGcJ拇(+m#}FrD_-@VDhAx'N/zr|PލYw@W{fv>0dG6wI}D4l^5Uy=]8lB,G Mt{8~;} h~443`44b)&&FU݉i-|-SϾ!h奾`wH[Ow)“וKvt3Q//ad=wLnE5aMycQn.fvXJB 3A,_~j/_VD ,M4|Yk")ZIЊ -D捣-~$qc祫:PacSܣVrvCd:aObP*;҂ZH0a6.0Iߪzb* c1+j Y[xB-:f2 zmucx73C ^5G*$"te ˢRDj4&P,.`YTq-c>M׆Ё!"Z3]Y$xjFtUǏzWB+~)DaE/;&\}*"sUr*_6fB+vhjCxݦ<ʦS3 k"n;nO@*Oҏ`J ρ1@9G/m/471%M Ga1kxq,0%yc}?y&G| p,gBdUrc6 2rrl5ɒL$pyZï:$<SuiEBM0)/ZUcNr;"tFZfPw2%C X'u+UWs!\=_QFuSZռ5_[ᬅtoemw͚BGLW?o)[<+١HdޗO>\% !wXϳ^M0`+J70) mGjެUI 5V%g.;=ior!s1}-<QûIbdzgLe:5 m$^ P=nuw s*9XǔvBɷer foT:zUϦO "GS.M14[3&t۴!{ߡ+c/y4A μ2폋-4eyĢ[! (ڟF0w+ew|G. ުڀJ{{'Ft hɦ|U1X#} ^/_ 7V\$A}u#_`5w͛bwBsSNؗkJ|,qnu;͙ rQRf q:ҔDb*Z1 ^s 1~{w[,rNV~Ie'po_)Nqa@V«Y8]C !xit.Hj#:y_nCgW<kgeѝAFUՊC;vd{]0. :37w]6˖Μy4T#'Rb%G{~bI&԰|"_O3|J[oJ-N'? <bC= w*}"&{oNe> &Bi8)+bpuQ=d-jqM/1Í6A9j?h2X_CKGiEj~;E҉2_8=\L̪fUR]9+nJ:CbY"1ZǁxN6LXW3`’&*ʷIgA)W,M-&&K <_a( 1nڰ1N3~H6i VscG%NCY؟baNKc_}-( Y=lE}EH:}>ጂk,D kCfSwhnwR%Qr_hasq5#WAJ h5:`,4 `t#뀱5H@8ߘ[hv)_YPs¸QvUe8nbr \ﺇc?@pg\ށ85ЄsPG>(EɃkJۭqz}`LwpcWv\;peŮ *C z2^bl+Pa]]`F$^ 'mLFF(ZB=]鱅FڣDyf:B=ݩt, #Q\AӼI"W%ĩ5RP)*L[m4i9xֿ>* p xtԾ`~YKKXVJ.⠙h )d6B t p+EuBQmw`AF !)紴!itf Y1kz5__]FԀ )m/C%^"MpPl\.9oF\k;Qd(оP'LMR1𦷝t׮fO2>hR2bSهa'u_i#oIݜctG.8>b'jz##_SuwbC 0) E2?p;hH*>>ŗ,磿adAv_HvV ϙ9v2\@ nǭ;7'ڦ>]E~A,¾,ב_x5e(ip) |K4hh4OL#v=7;5Ѯh/(L?cTT}L3*[) QF7{ sfLZ;g" 'EFyOCSCIκwe< _M#\F#j q`GlBsI ySѼCS W/HY5k"Xvt+g_֬%hLQXO#E %XN`&7m`#cqwgϒ߶60 =ceD@=WRi,{y,%kѶQw#+/`Z ih(pDC| hp7.VDK#H玫ڂ=a1<wddJH.)jQ4/Y0!ce$1s$&׫0 O0|RT,\i40?,NWx ˌ / r/CۜOgt2Dɲ}M-I22Z殡r*~J.='?BȜ j?HlP잦Cw~u pRW_\*d~v#qKRB*zk5.G*Io o=6e2##*S+ (8]gHE! *K|DpbSa g.ZWbc?1?h?5Nג zQvPk/qǭd$}!g[to%fJBja'[> SYZ/X%31#U(FYrVz6Ro!ӎg0w~/0 0ÜbXZ8v_}Ce:Z^ 84=02'00t+Q!cS>P]ܣpSy9 (!v M|Ј%Ja bQ ~:\E_y $l4xvȒ,p"&;qq!X%dh#ƘʦCBց#ܱȰ '^>O엾_L{Ո2qmws>/A6Y"Pp~o$~ʚUgSU!ZӃ(.# F)&P?YPu[eAafЁ q}g0OQbS}B=A#-=Â$mAl]j4U $K({?0F$kȈfըv|lv0 &v^Duu҂M]')w*b4p]<ڿpa^Coǎa6MǪgН:w}څKw94 D 2 Y=ZIX1~fXꙺ@}[nVSgqvcݒoX_O舷,k1 Z> G8FiU#~=TX_My+ V= TAٚ cM ͐A }AׄQ:VEaLioD9Oz#$owaMЗpJSpi 6g;g=s+ߦ%ۃֵ՘uaLj?¦#-@|kt8b^ =OڔtPrA{M[2//pw%Nl'gE`a,pzZ >],o{L$WOkJM6en=Q qFd=žj 5]'zNp2ݚ/Vڧ^U-$>gllvIN)|. kVO#,Y|U*rt6g DI$b6!%ŗf0- ˝uq&`Ϭʚ#Q}1AXexNP;%c'Dq~|Z32uK·lsP^ (3RY`h ЦA_U(t?M:5L/ UhGr'IS `xurnW P;}g=WMIǿo{7-;3TN7@m^W(*2> <5llB[pLPWt8Q4U`I`5E]`~V/bgb+>oߖ:d-j1 T[|,ǿGÃ+Š`NGmXs*ino繳@f2?f,H-4.0 N` jpdg+}}pGh[Vz&!~oÏ"ӟ#%e| epO^daP!3=ZoӉdUԗu-oivmc+_W;lܟSchƂjUq<眆x,~tmڤNgx(M^ 2^ w) ,QLRX9J(E~1hPMk 磐XaUXe8 ^٘nN*&_lM5mx+[g#&1ψM-s\]w[ofFwځo(.V#ii_'!  Dʐ(- ج;70 ܚ8q0xdT3u=M2 X'f/$9`C?'.&8t Cltղ][ Y~' |%Ӡ#]ͱz Y%zt.J}ADFhgU+h1I`fKӻ-"ڙ=Glg~K1c!// yW BӾ!^e$I 佫#$uq @J-CQjy_Ҳ EgJcpQwMeߚ2mJ yDSL&OZoXESH}z+1g5~}|Aŵ4<~ȧ#pC& pįA +[ZG!h#v5> ޒ,KMd̲hUQg#Α Lܸ0YV/, CЩ/ѳLlO,o0@tㇱ 428/RU:O &z٧[e=$ġnÅc(>E( /GwSa-L(`ں#/ 5rӌ˧yәh^ "] bx58S(,h(>qلAMtr_=jP>mHYU4_#7"Wo ??X:^aAeL.rؗڼ1}Ɉ&4tSfC/ɹg9fG?91&h/D?I /$H3EqD#D<.Z,YXSZِک孁\ Y!h *t\w4>X`7vP;OUtZ,VQމC\Q:rIܻ4 )G.gZh% P˾[{ <߶e qg̲ěf ˼{G$i/Fj_H!$L*&)ǙQֽr ǯj -ʵ9'\ &2&~fn}`bO0g@lgEV\7w= !anF:j,M.ָYc~mN!M 79īiYj_<~-m@W@S.8i}fdzgR6sA}`{ sHFs`f`΍rtQBm Nar;^u?tƺчcqlbAEWg8 .Fw)n{ΦB)G=' HVͦ) \z2<$KZŒzJ֜"2aG&:Wㅛ>.MN*s[T$ɻn>!cHRQҭY2&{Ww4M./vşsWMJ#U([|pHJ8SrG5wfwurޢT$l,J+g)e4EE:>b>̦ OkW_sݔǂZ~3:?d$-ʠf3~_}"oFH3ּ!q Kr,l M^rRbΠSb??k32o}SBܑ4btW5k_!u,?yVxG- ͰZ yԮY+ kA;WSFdb~v"u}tph/בr4A*8C.:4E[$q4q4Gsޒoz?vFL\hAy2JrL녙 v?$KJl ,D8-p}6S:ЗUB[T`볲'@TW[ƠMxEy`]RI 9:"mjf1SG EFHrz@2 sOz ٲ$'aya C$?KuL~go5i*=lֱbVwF2~,D"8ث _$Pv $Hէ`;7Tb@V"ð3TOˀ! wmVdԳԤ[p 'G!T{{toB還*]JK|YH%?q^Ite{WZL~+@h(nHztړ\ܿ"{9D طv:+Dr L= vXHnn9_|| |Aҭ^Pt5Fg?m1%b>-p@;巯8![@ f*; oפeH&@Fwƙ9_{9WTE+-!niDl4D헫n3-E:N(ǀo&"M<4ضO"V Ĺ]xKM5a*B+ʛֹB:~t' kWG<2׼Aq(%)~Q,Xr3dA5*GZiaqX@<0JPt6׾,Н } V bIFqRm* $FfAK.&tBW̌Xjs,ꔔCFrWE|E:س#Ƀ; ԭWf$r P:w^|ķS C<(hk'5$ By]M_12,~Ra^RC[NcnۧKlՁ+ZtbY y+= 9%/D XR >I5˓׈~{/`'w>fT\$N(Sb UL:순TL*pXhzԭLn/VXP.#h1Rg~9y sp8{qz=#5hyj_gza;#c["?IL׽xf)Vʫ+IǍ1.6p]`XA\|Ȉʸu.U5չL<Օ?v$lhG0¥D҉ FB!.R~U`̸*OKt!JXaxyY_|1T)vluf7 (⸕89fZk@:$GN↙(*s., KqjPlsfΑgwůX̲'Ky5FZݳc -Z/\m,O\&"Pd V!b!O|F:l4sLT M{f&H8DaQ= u8 L,/qI.L⮳[Q>D|;.}x#}82 *t&ِi'N,헉 l"*pQpۭU܂hi+T1=q|V}`ʸU| ͽY-˻g/rpk1>97'::b!< Vm ~9IdѢ 4byzsTȼ58khI.%o1@wi$I/JDgpm,2?e }kY8d W0?Oau dju]l ޸v@4Gaf?I7 sLQ h7ٮJ* `4@]ĆQz٘C|Ulu]W9RDž`Y8/{}y| ?{&3B P8H='~S.ÍH5$=c=DUZo[n0xiK %NvG]ug%@gQ~(c=1sr vUm^FyA;I+)Rx1J|X6岐oNm9Ay ]bϖqI}̗+l$m|Ftg}~#˝ W4P6bb`g'GUT˗咸)%_q#iWDJy[v*bgIY tZ 40𰭧#<{5Rɏbqڱ0!h@R*)"4z 4gE"<[ԭP{vC[K[!iLJܝF7BsT˽ȿՊ4F$9ZR( ЗsRsaj{xLД0G'ۀvb%R\9i5f<(J2NݴM@y ɑ-Hp,DD?bzL; HzNF{ ʓfEFG8x~?i9G*dU7"V6(*sD cCe{pSCvdQ`+{.xi l[b>>Ŷ'9z,6p eHɪydM6-OLeD>71Ռܔvc畫ӟ`QxM.լY{{_HS{M9-WDwFU<;meZ ~-F,/Eߺ4/:j4|MMdFE w&!ã'7l:( Z?' m˓t{zw+!㖚 pȖ,23lij\Yɳ#h(ХtCFYh"SsE xg^Yj5vW1u_+k[X5sB' 8&;n7`񞼿hfTarj 9~_%1fdaOd @}L3{ d*ʴ꧰d$dNZ($HJSH@4` r)NJ46D&j8;64ټvӐ>vN P5&]ӌTcZKf]l<3 Dk@yv=wp 'q7c̩"uPjJJ\k20.;D'9&>'TuD7i݀d d3>z"Azjz~*2+6 PǷ_q:-84ǜyieIp,{3Ty:;XeX<z0sWK^`Q? p*=kbjSk&MAcKt]'Iߘ׬N?6k}.tbW뙎H|ސaR';ѮlfL`phFBi\o_@miQr9̈M,Z5ɾD3VM"A w!pu״Bɻ2{| U_mWwi'Ϭ HX:-oďWYM+YK?Hx52ZF.imT֥y,ՑR(Am@וw0YG/k2M,2x7:a7R T73vQ}Qvψ}?}-A U g9DY+br6Gl6+V =E;MQ98<4+.Dmq#*+|Fa҂c#"ua1e s^g;\)ai}ȬpxP'+'r@y/Z,WsȭF>&0s6nJh`+!pncEZ"I3@k UZ\TO+*Xؤu# y%xz-FVejOo /o g1_l]vב1jc'_[;C!^ڊ\ۡldQl  ])m/2+d>~-M^Eh>'75~?5OL敊mlH`A (ٟ dw#F= ]UYAݾKvY8 |XvMkLk]N*T[ǏӎǙ K0bX0(eiHvDrR6L#aF!B猤͔tN-4Bx; %E╈!_In)CZWAgv<#dF:wUZ^A1V9A#aVo阱$R|=qw(m*$IɋlK~uN{ty! EA + "XZJ1o{_쑕_#im%O޽XGؘ)K5.cv u)(Mb:; AgbYQd_t/rkV*?!+<1.g^qt^a 0O'wֈvС)M;o P.RxhTY`TXS -2v#rZ,-iX%Hv3bs[[q!Wl/?95ZtQ5{TcUYM|HRKCPb$ͦ~iFxNpf='q3M zJLV k%3gh{?bZpcS7%ath6#F\hOD1dt2,@։_qm%T *cb=U` oTwN_d>#i$TlI%Ȟb׉oSq"@- ''ۭn@#'>!Iʪz:!փ1t%D Y2ߚ.J`ׅyS D.R\ĵKF?[⒂JXr}g!-ߢqQ.j* HAUK `yU+QGci)7F# ]ՇkZ+<":]HޞAZ;;pV΀K]t`~8̑1~zx7ldm^|r 9.YvZZ ocL|Z /aD1 !SP70qٜ zMguqW4.ăm/q}.JV,in}L 7Ow̯ӝX_M$jDĸ,GvYF q *er7nuf45yTw:}!0>.q,,k(K*R)Rf%yT߁7΂̉-|0r,4EM=vx׏@z2XKi[ cD jxs#\̋/_WPEJˆ_J <oUTT7?3oʲTS;Y޲_DFh5c.z)>Idz6AW_II g.PP?|f.RLp AĪ!~T$9\d {"x3V D8HHsıi 3W@cᙱ焥.FFlȉȞ"XN^a(4(=~_ uUilUd9~X < T5∇Eijk7\겎; S'w@V_4ʡlP5eJc7FL[Cۺ-MrZ./,$.?i]C4zMyxSXEH t OArOí1~Gmg-XK  Ǵ`gE?,s@'TbEKM(ptif=X\\[Q-,MpؘF􌼴?b"tF%E`n}r\sޖ<@j/!{қH}x>sL=fPJ7th#t-?9GL?Xt[`խt`bQNX˶B+a<:80?gw$uc@p!BY "LSRE -&|JK1dhNdڽdEvk`Շބn+N$)PVjyXgZMg&H #} RY:9/jvqYbYaEEIT :jgo%I_Ie'{ :FF˪/HbIYL3+i8+:uFG@8?o[̜#J,i~{Ib0kG}n h%"o$TanO-RHzvC2Zn6(^@hl*+s} ܥ:n#/CS`dZKwq*h u7;ve z5OC\i!Rxsʂ!"pSn.&\vť.MԳxh=Tۃ28!c 91ڕ~n2EW0ME_-Hr`~[q[gWVv̜F F8q]tyq 685ԼX;r1q#@VÜ>'رZ=)x޼ޕ'UVD% Y57oz;UnƖ70;,i蠗 ȳC[F78a=1sRI}x?l} ǸI mHCs-K̮W%P9Py&$qo?dKm/4s՞9Q?7WF cg(d#CTHAq-JQa4mˉDkrXL o}w TOn񗅽Ky6CLUe#AJeIU("jj<>1 hFX:W^P0|Q=Oōո!*; =r'>įJէj12Z~Δ+IMFn.G>wgBj*Q*uXOrL̯7uYKԀWousž~4^'m4vKs/3+,%jDb 3bl`]zL;sLRU^o`rOY>sG<Ƥ>Ca)L >= 5r& Nj\A> 1v\xުp!Qj:P>S DM1RDC/B> 7OO~ၯ9+NS]( vDBICSl]lUt5+0]ܱ"}3HAS1.XO[apl)ehUUAI"͢@{}XݿwHcwד9L4͘Gq5d@Lˬׅ~@+#m.``΢V! 7,} Z %@]znp*Π(ap>K--:7cu34LKd'z;p3C8:;lv5"?g`uq8-eƃ1݋ OkQ.UU/$oX~t,–e7h6CTI 0{ս4ܷn,k| s+8y"7li0Xq+U)T$ ܹĝó/w %h4t@g{F&`%ԙaXpef&'d'OX (gYx[:PWAYBƭo3,*K@pl}Ip۟%wly 移f׍"VwG_dXa;[bwOo6Uz(+8$|KXN#q/#$/0'[یǚ48$VKLN~X~ Q8wכk";|5:hԖnȟQO$+iRDhCkse ͖^+ !Nt8b̳-DSY(DJ5,?Y/ "@~-w|(Ca&d--Qt߬qBc|m"Hbvш$jb;i_g^}>6R!n`tF P^^@>eWַk\6ox Vع|Wl ق䒘ݴUO{Z? senFDbKM-hڔwJ0y-8 8cP}(?rgo\8xf~IѲ%SӘ_Bn ͧ痿qhezvX˱ey9Ω[rs;C%XNin-u7E{߮Rn?g<"+<'?) J0mLuF`nr&m"CɀĴnJDGhvM11$pid͕$8EJ-`"Ena~3G0fCƋ]e6}x\tr0_VʛPC 2׌.aG񵴙1$|l qQ9y,Qݏ|mbϺl8_eL>x}8΁V̴ b|/ǢnI ,541r6$IPNcqR˥y;~36`gEBmJH땰UY#Mev嬂{zy52?4u+1+B@쑨*7OGO45kWX.sۍB>p#BQޘ$1c;u/$E*gٽU.&=}T |S&D ?%*To] FdD-*GQ}&8/?!8CQݧ޳VdOLNAC6daiO22GWYӶo'uN-1ZkHgHl}BgH'5vXW\jru;K^ðՍoGϏ*ŸT5R2 қ}#X3MI,Mޘl]0ԍ>ZֲveAش7b,Y'-NUtK+6ZF)oWW4QZl1!ER@G XʞF"~ڑt`5dtJCPNx.%5# N2px@<6J}gӘWC"K@ ;@7'ᡆN9}S,kf$X߀Ue/$p60?NT)Uu(0k/q70&Ǯ5g[V*C3ϒ v&;l5pҲϻ\38NMµnN"HjQdϝɱ']EZ{J=0D^쩝pz7R(Zs(V:'8 }&1#,@n ؛0>S-H|QƱ#ha.L޽mGKïAYхjCa^Jjɿ/",]C8bx\b1?Ux̆daB'D FC9a%Rj4Mca7Y5gӄ"^/.f5,PNicYTǏӽJW3*P/iXG+.fy^Oϻ%"_cʐ/ {x P`i 慅cJ>E Tcd!ͱU|tX G7LAp4%fT㯀뾓p] £FMxĞز8>Q@ fҲ.e<+xѤժ)Ŷ饢2ШDeBv$z7ǚqH&%,^M?9&1\kOS &y1]I$0)_aͻL ?흤!3@S%Ұ93Yh f۴̯݊gy>v@1 /%8o# :PqU 񹆔agX?3KYA=s&\8_کf _G%j%t'ڄaJN2fy({39&BR=ykFZir9-e%2$l\# eZPe3(&q%;2|*TNM"}Mww_ྷr HM /o4BoQ`&\uW\8%3B +va']I8 ѬaMB 6P\*Lo嫾1p?WS*8UqL<8w{a&4>05Ջjp4}WqGŜpҲhU?T  u{4{@>rRQiO#Ftzwq>)*K\7S~kSTEUF~ßTP~7SO&56UAe2ё&[[#=kl(* @(1za {j|^ 2AM2uf_3&bJ0&`DKM2[<%i?6A&k)mN\{)O<] XpoOq(}htP YUgܱ%="z4+c6Xbh<@u҈X^ F1s/4w4XpLIIfCnj?"QnƦ䓪eҽ"~umZ:idfV._]9"pnQAWbЇ > xNna"ŖỉP 4'U /㈩̗ky61TXFVc}|6,c( VX`xﰩ% G˳Dvnd mg($KQbL1:0 _ dhV}i1;dq#=ӿP88OCrpU :.LmmJx}R;5h4Ϟu3KauB1v#M3kY=[BZ;o ߧt΁> taz[Kaksn٘Cf,G:dϪ#h)F,YΣ:!V- /KRX"e@ʰVaWLZ'^kgY &}FhA–Qn@~xE~w-a0"H!Y 17E/#蠒- >t vXuAͰP̅Z)'12n8n8p]Wf@ 5̲偗~M^ | miƇՈؔq0 ~mGC~lfen0z@%]p$> 0m$dLt6)FGK7py$”phpnԔDHmj{s wPicB(1q:0ƚ2PuSaomi6kTAyt ޜB 5f&6޷[~jefqMu=1I 1I$u\Xz![ni3֓.&+_VLIYSFS55~`l<+dAgFݡiu7wzi |ƌ!6-j!oa7s&ΥH|[Y/>g",ԄEB 8L^GAO)ۉGJ/lyO=P%g' SP}#TE6{ x1`wju 5sg&l >챵nq-zm~!1m?U`cV;-C,ZFL{H6۬j˜ F>)H^ 7i_;4"X]STPϐc%(s!Hc. ZHqp4J]Tx7rpRAdd7? %Ew#c+aT_x! zߝؗV'lnڷM¢lٷDz "Ӫ;dgIs2&K;o x_wGs7 G"v&E1eL}5HU53{: CvCdĹ6(ӵUA Qk.P;UkIWÍk`ÛVeNpã]t zd9#J6B}KBd,܈Ԅ` X,U'[`QS:N ROuVTvaG:辐]sOֺB mPs-,IμFTp 3$7'Lq ʏڧݶjJyu${L&^]++;>H|^iɖ0[KӋԗM[Sl3+}UONyEip!~5öK1XzɾlBOb 4tw#]/@X!aL]B<@3h7p::騱PDDh+ .ᬕ]Db^6DjX<Zu;k,2qfk439r[J [< 2qŷ05F5?DȌ>[$KH$ԓ?{V=x@pg% V4븫 O:wV4L{~=((0h{eBg:`gmY[W~ll M[Vd0ĉFPٻ@j3o]wb4Å>v0Bp0׶bh#e$!s;FmDԧ( 5ze%$,{9֨!|SB޶9Bz"ޅy06>b&3O^{AAߠH6[P!I&<W'נּF{Ab)q'D0-$⸌!Tg8?Z[.XI!G⭑A`sz -CO\ }Ýz!cPV0uOwoi ^bݙ&+WImBd"F[Lñ9lG1#4T |ջOm_ //,k"^pf(]A@s!ٶДuZaZs <ɩ0uӘɏ>/)?L÷}C-Ǐ|JTu+JžP QKd6ոliHr0'T@Oh4$ȴդ^)fs6F ?KiQR7@[pwF1)PgXb"2TQzV!<߃z\,>hRj䃵X)up BY}aMqvÚ)=XU}#5j[>` 9Fa~`_%!Xfdh`bxq4̀-(DBR;rC+|J /LEaU4 6غye6ɸ+2z|@s.K96Et BIZF*eɹεʤȟȓ[Ҟ؊K@\OlCy1 ]TR%'20@]Ȼ7H(V׈43s|,v K ,$nYGPԥ]zq,X5cB;885 $[)%IAź\ 29'2WavO"9u4(e}rw-;2ls후Qs-Œ`aLD Ѭ=$" S1!q! $8Jg!YB 7T(!(N*=q1@DzDX w;4Lx!;"ʈ C}AK#B#xkĴ1][˥\mcWtCHp>~J/}`>go'y%xg'kAiv<-˂t8_5s=(*~:pQ w5WkmJ\jMQKEkel3jad*XpΞNbDZ°JorA%l  9{8~r>oy^jh*x Jvr?8}Ȥ)&qg`D6pxbRbp[ ̓[zp %rLDkDm</\TA7Xܚ[-hsԝ /HʾXi%nj퇓0 VtX)|pqMȷ,cYZh_},VMDn'cFv-W=9}KLmJt{P +@V-c+ՁzK~1U(tpARmFb)VlEh1b )P2,/LAH{9)#hLD.8 5Nxt.ahDB쓰]EfU4#‘8%͔P6w/s%O)Кk{ z7^4H`Nց#+]\q) Rj᷆b%R7=DXu',^ DIQ/t(lN?υ%B-R]u%(^^ľ=6]{bd?$Xj"d43ۊpn(H7/0kFwM2Qwt5^-xzφ%АD%r"U~h]|oʾKVM]]Kǧїjso9AVk #?Ifi"$9!\8yx K)%EC%~4vbv ɾCPb"=&sCɅBU-ZRFf瞏Ά#NGfR2_y4gvIyF![s[qZ>!OtXua\10A\_._aU(rcb6}W{bEdԨ+P)BFRR㔹Q&tIcYF1f4=@s3bc<9c:v$Oa;=lun *n%Xmz?XǟW\3]N?E.o4 IA#:&WWJ3/2:"IDsRh4YMJGKnp8o IZ%o9Q~zHws87$DU.Onhq7]ǥioo*㜁?#FPkQb|`Ɲ$BM麁%bF٫|3':tF( 8t,xd񿈎):bJI7yVX #dQ]T"]҆>'pKfR_M., sͰG{1|\hjqb&E%2#G=,Vd9٠2GjH3"O;` ?@8nnL =oJAMrṋ% /_Skn2<\QO&kv/H8d8fnBF.W aiêdTz#k't $|)Sgu:9Եq*U3E|>)( JPŦ'Ҙ<3^}YsL45ȤJI{O]X|4TFO~e{Kj7( Ber~D$̤l ؽ`FjSD#1qs˹-gc> LVj70G{6̄sK&^c#K=׺;TH]yOt;B< Xe*|4ifAq0ږYWsAb(*Y{! X&а"ɿ sα9H?G|%D~?sԪthtoNBz y^-t `y9KXpA3Ʊu1/YI[‹ػ|;6)#~ip/Wyr&i쉻Sk9;%T6/fi!D/Cw釸[3z6uX\by-YGԧ!cעm#gMDSa1P|uZjԙN 7TwWh0@ yni>Ws}(̽:Ќ~=NF0) c6˄dIP^nif!Nt:;jqɽM8w0_+{cbe_ahJ)gJ3") S~9hx@{rɉulH%눂OifaĹN- .DW= ̙>g$g IX_ܑ̛F^&IA ע,da:_҉@QR~(`xvM3WYUW1]L"Y1GNbۯZACϴ i2:&.M&"%`֙[ˇNMsv,auKu7\&EciIXP3hZ<9Ȩ" ;GX-I7;5za'յNݟ7^:"b.9$ơu |'he~x[^-\S{ fg,ӓHg]ӤSDۏ PHbgRhά] ҷŕHvaB\;yX)'9yPǫU e>=-it;ׄk+׻YMb  5!AHIԟˊ(uLjԁSe|zMQߊo0NfL5Wl?jT-Bjbr~B^x|1=%پ}٘|4?⺚KUٜM; w=~5aaJ̅y^bWqw,K٢0nT>F 1fv&GF ~n$}/fv|I7J&532?}~֖´0C!Oziȯ&܇UjnU\Q< .aɇe hRbrP*yڒ,du@#rbb֭h7@m#xigB ~Aַ8+ϨbqQXѹP_]/CX%KtFh2R?fNL0X8LUg5AF8& )$~s9NO"00@=>D!}Jxw%L04o<~&& l$@X^3! /G iGT Y*5 [;E4X,O\0|~zAy~ޔ1޾_[`; |N%_}%:]uf|!s;㦮7 b1׾GZu_ DbAݼۨ8I:T:mv5qAwmĜQ?(PgSՈ3$j4 'FZ3o?$Рen0UM8EM\OTZ}GXVb9As45t>vR3{aۥJ/[l> ]RK9&Ap 9 _eI>cXUJк7 ul=Ws [70(&4ko佂HKC??k#_J;·7~"ؾw+8ή9h}7uGєs7RBL1|DD_@ޙ4" ŚK#jXLftt<;2,A]}BJͳ"<>z}[J\QG+6ğ(2;xVizukk;| o^htz-0鈢L1779Pzڜ GgCCĎLj'v 0ʚ}|o%K6Ů`$}5=E~!w_鄌+#hl{'H,&=B*un9G^Y:|3GV$ rNz~U5'4 :~o6#-͋TrT<2GE&Q ݡk{٢q!}Fs*05K 1[ Q}&ʷ5ϙ u#9qgf7ɤ0(]9;jL-X%c-Wܓ4>B1he_U|O[{$ ~(&@?[>P0gG$Uz͊emYd])4'*dE`sxL-Stry+D=C߷"F2PS%#q W%kLGdCץB&XPY*ܗ.ioLMma-#CU,F EDjSh\xi ~`;&Ue`{ߎp c)9</)n5 q,"Ü,"܅j'#$$UC9p<0> 0`a}ל g^?3q?QشUQPx~|݃@+tA |ad{#y"<߬C4hjT}jKTzot Ɋ2C=̀x|- R Oj-ToaLP&-^&EK.q:b*~# PR_:WYa2Ո/*gW ^*FKd3%`ҙPAN |%C E1(EMJ/+`P,v2;bakĉQv2=OlӘ qђBt/ZMUbK*YTrl(AM v0iy\U桀/\t4Oi\sAy?U<aY+YSic?1PyvxHw 6*oV7!)SGe >氐eY!U<2sHE&LX&%jk+RGI.QqF\Kތh%1^4:'={CBƛչC>),( UFR[@ٹ\ Em> UAgigb-VՊY^/ uH B$򰩇׋;p!bղ DHynƢD+$ ;AVYRiMYOAo73'1R8/\J- 38^K'?QY=AC>H(M+Oc9lUu:ay!CLۡ7I>b>܂ґ*TzOW3ˠQt#3$ۀ&/zgSu-|o+@D٭‰7yz&9&]cP`sq/D3P{qv@Mɤ;a-Yb($l=un$IDe. Im0:X( ?y{;b5oCbuDC"B|X~hg gyHM*1jD$}$t͕Zŏ'TY_N MySŇ1]|7@󶬬]fjV2b~n@…*~Xd|9hGe@Oa^Ht|ʨL=%H[zכ57t[L}?diaXŘAA$6`j]Rke_{_&u$PIrq'ØWn?H3Ru]<>U@{Y&lFWvV籱2{TvJfFPby gu1?U8Dx": ?EtbiP~Vx5 VCh>?+s;} jI+YdS-Za Z6d2NNC@C{l"uO4vϭj)b|aQN:7%];'O?c矠1Ѡ.IubS3nz ISGROѢ_WMRևxy?/lf#[d-ǣFYg+e@ 1!s,\)xx3dk B!"wpeȖ?G= ԉ qπmH-$q{Zt87)-"W`{qd遛.{oj5DKO#嫯Ւî6 :Ot#!7״'ZA%Oj ·==߼ERl\޸MF뉯dRgI-4Q "ŗ:*gBl{;py4.||}c>$,{uE)8W4vOt>̵dF)o:P-V7XtSDu;,EFAxv1Whe0gX7UY],A2gWu,i֋(2Ýa2mT9? c,2-pINȱqtC&K΋Ffu^ zH4R+Vkst2[;j2cQz76^)5LՖp͔hEnC )M c2<hZ$LN'cVݐ:Is_d|X:dE9U@7@fא?4Rot܍'p 1n nal/cdNOW R6ޕN|Æ.f,A=+flq61<Ԉ6!1.VC>jlӥ G3xC %dZ4Ii-&?ŕLdNPmHe6#ƞ%/jv$=OYuttHcjE3qSh9icnS͌;FXU^+d-qDnnHSypk\X}#`v/|jBB >e["(FΦ).xn*Sz7CF,?rx6α[`9Z89Kb`U(!3L{r>DrD(!F^a*  þUi LjO VrwH dEach2(6 m][*C*\+}&*poSVIX0U0R妹3^1%'tI130s@ڛB7UM:뽆,5j ^E6y|owjbuʸyx*TT̎)a_מ_D.cRh,a8YS#ww6olCEUY1 .Iy׻ްL{bzD(.nccAt㻳B|SY6֪ӂm"`2?^KI fWb-UdDa]zK{SvTIR }j Y_@PwQc|@MO.gO(5N[,L[ѯ4zT|@m+I`MA,/_aܼ*aLT]4 J5Cz@f u~Xs@ߛ)2F(:*%Kg=}6U{P*]V̥Ao܄~^^+Syu(i~ e)9MI"0&x*G7z}f(9/a7љ2)F )cmp@(H&ɥL\&YyqPOبxiS7kn"&+=#;o$,F_`6=Vnׁu?GRW@=0q>mSHXw 1} 'nxNHj+4G/Yя$Xs{u1P~F*_\PT0?G3%v~kЀf^- KA bK?buf찣IFIkYy!Q$0CbwORC.Y AI)"M|KJa<9Yn-Uw6T%Y.oزCP^yf)dc~{[pT ?~лrYմsܯ~i=,o:+ĸ  T*Thb},K8Rm5c*&@:nqzl1fXFN]UcqG 4Z< MNn \sףدsռctO6~q3e~'n[DR00%ؖZlOLVEREakGN (sgf1bE4/+E+\l59a 3z;Y 3!$Кỳ'˜G~- FjFVYNFmcO=an,Whp6,j_c_̵݃ճC娔 3̍ݝ1\' _o`N2ʋ԰!o%}:gqϿO-]2O[1z IH(23uDVq:0[JjTE$)Xܗ@@vVo6-gbŎO4~um)96UxANZtAH5&]gpkQ %6H)"@y\Z$wb6s""4:H="-lfZ ` zU{M]$)5No@pg"}v1'Լ}O/VK.Ahxq%f7>Ts_oa 1̖G{#SiCV(?L;(S|!q+fI϶-4ҿ!1з#@UQ0T=TB<3ZhǏMu6KVèj^k`X7NWsBGcLQX_zqManI+OfZsF,Ө]8!DQc+ @c"-~rvݗk;h78ЇJmK(Wߨ+^]&!ߋFϗ_n0Yx-a 4TgV6 !H1O|^̿F>$zz5kkcL WbgO5v(}1DLS)[ &RӷH2XGqwdp^rEʹ+ BB/6L:[#Pi |KrPV,"5>7{+h텷qs~7Ǒ!5:!MCSx8^+OqOe>e"xz=?~;0eX;zbuvPZ1ʞ6yeDQ ^g*KZ9 H`Ca&+?NФ=[bDqi%!Ts&OqzXbJ m9h6E#Z(D퓜-piwDFPj5H1T)A muw8|1E'#3VQwB*$K Y#Hcqܖ& !LE^|L ֆpYc,w)#;TTCu3E2]l,c7}I,tX 3dVuQWZT\, 1+m/?[biuTYy*nd˾7ft:!M;"da \Ae~ib+ a&`g& MEԝ;'#sw#Mgh9gWK/}a5Tw $763U$,@!Yp"-}bX3`K3(4궚_iɮh[>J\Lk  IE(G]ȧɍüPزMk.M&jm$c5}A;QNt^= Ɩ^r* @S(ni I[F)kM֍y2ԃIaWʒb'Rm_}`U; PW3b󩿔kf QEDl9"yeZ4I+45 L'IgQ,Eϝ 4Eowd6>j;]mNz&elײP'\ +niԟq_MQ@P3*Ef],g|?AL/c/ 2K/+ ԍ8S⣛3l -8UֆC.`#/]bxՕ/R.8t+W|d('Ҳg{*Ԑ6hxYjޟVRb"в\;4}~`X`ȝ&Th|VD:[\xFBri(pLu}8L@bD_UTdMoM?gzpW{lBN2;49/Zv$lS{9~=nPP:WU =/y'`} [_Ic}]ꂧ7)c6X nWC?0<+0 e*k]/5[1&4 (AG2]w46z֢^ĢxrEF!ko\ji$4oFfry?=gx]D&o4hnx$Ƌs@q ;|Y=S(?reFhij¡/?v DT@gC_B7#f(ۧf}mL솶ys]$ Zng!(^N/</鄶x;Vg\l*'wRH]hH pүyN*7S6qAXOEiA3M QL#8gfHS0UQH@nծk_L@hԞϐcѭb\&wl7*YikG/Ε QhuTgw"LE; ?g_-IN#R7` ZSЁ0{]W鈼M%?ҲEewִ2G\X\eN1E? kI.inD) a.;צ'W|݄?^X$wvϢG>7 uV/g{2FF V&q牳~zࠎm'm@@ dju`RiITA;L3L(r-f"7&3+vPaOTx;e˦' KdY౧UOMtȒou/ ! # 9G'#joYVQ=5 !j*l :q^rJHs39[.Ž9b5жNT[/n#˹dMV0תso5CKzv\W^WNF9 l^3&xXّr--G_>,*efbۂFC0em<Sabe^7\ȨpOxwWH}Y>j*hI^6ќ3J;Bdž]Q|9:+5-}.Spb |^Y,-ZXQ:KoӠ\;GBY t{dj@+(e8Cn~b{%u0XGڣxT%`9*n$wbtI -4-[4vv=Kd=~%Kxu:zYzJad4f;#,IGԆ^FŃ*JfVtJUp8/N<| 06D8!+R%ؙ 08E ˔`n7TnΌiJD!b5ט(S&1Y LYRίCn>$q%I2Ѫ,'bQRױG ׶|\!Z\gR̊pƘ$sNBp(maT6(Ni;.DY< 2J yP>6 #3}x Djl:is+esn =Cr'@k mh]?g՗O6;e C-?^g-#8EacSWҳYtM[4.5YӅ`'eh;ڧsTxj"ՐܫF nPLHT{te5R&T!PKSw?c'(}WcQ{V p/6$;~恰9 2oŎ|aeWdckhCMx' I%~^ؿv8 GRVfoL5+\dѻǻ\gT쩅1@_[.L֧/YکLoAHoeV.21@EQ.1y=;cM$9iọ+?,4=:wKs_W~+6=)s&ֻ7KG>3%*빙 wfh_oW" V)_C^nnO`Kjh-@roqI݋0ю)z y_Oln[l a 2|KW^^*U|ėA w p({?TaϩU>ӄrǖ o\o0+D/EE%`_Æ!eHD9y|`X@l[\&>ٯ!AAA8^F tذ/r(LjfE%H'UUh3'AUQ.a+xI1 Q/VѸȆCJzX9`On~9}DkdHʘ9lNҍÁ96764OWa "9F xR]ݗtAgF3$cMg.NIB8{;<Xͨ)1MBW)հ=0{TfFzǏx*L0]k%=B. 2FAr!hə!8CD@BBjXןQJOo^Nl|y8DA^nz7'BXX o:M7X>)C{Qk'Sx&gIG1 H \Eʓ`#̍{*!}Eab w3j_jNF=y>RUAJR#?}i5bXUǏlzM0mKG"r`2I&* \BSa6L<3F{?%aI<3HaZZ>d|A/cB?}#k? Dxw ȝ 7]Ֆ>B1$EE`Oǣí дLYXd ^^•i2)u%۰;?t6MsYKu3Wʽ @?%ӓxak/ 1PA98+ 4L^hydz|DuIϓ OT&!\4;g9>豾EBu}>9f'!{U¸9xU <~pZ+FXDS p]Փ}3v uPf.˜IQ?mt˾l wiq0rΰjϵDN*;A8j(}s fSZouBp͎ ϑr׬h; K0ޅxӬFXLvfTG"-Kΐl>'(H<܋Bt1nѫ?s4R Oy US{sj'MnN=%peb+B5ח\ }3`&p@1 "ED L-ܩ!yr+ށLz@ Fzv1p~K0U{ gv 'F'0.]jRlW9$o_A{jhBA_mBZئ .'5ڪDaޙ]1CIj QLUzM:%;2-L{ϐܾBnuӎhΡnJCvcWR_zKF0w7u2<*>bYW*=nU 7D[CӏV.#(˝Dt/$Ԉn#bx+-.r~ށ (Mtc5n$KT5 b8"~ihRYތ&sO$T\"QL$ķ.8 pU$M140}kO/s U"t8>5* S dž?oFUToaa&)v~N:1Tf^l5}7|CB/UmpQ}zr2=McUksa@sԻh[a&545հFc E3=TK0g!9@WO1EQv=dhDgMI+-jq?BlQ<YڟdIzIwxlLհ~Oc#Z;&:ELطsS^)HJwt"ˌQw>*4&-O8HN5pkp܆zLT4zM$n>qI?GƊy lmS}<[PԄB/e]umYJdG$u;\MqHv?% F1$گ:f m94JɛȎGո@PMYN>{thsYHU0Ezrț))]ޤk}%H#fmQ+Oh)Ӂe$ط-Q|6L62;%9LL 7CT`Vu35{ 7UdU2(A}~FB&~4} ) >]hAp%Bw]]s63aSFٞF&״5g? ƀ8~[+ Sn"<"Gmd*SwhGb{^ mi2yYK L/( hC[}c7s0HVx dk/wÇ)3I^{GZO/[\%|n۳ﭗ')T;!mȺ,Vn<7UaZ~6+#U#=*EZT4̎H{"hG2h:yCi qcN.s͂ L/seP$DREw*pL=޲Mn'#h>Kx";\I.(1:BP+%S YEoc*sYGpH+<7eD0:7Md܄4J>2vŘst?97/}!-P@=Vxf֔0-4Ptò- %ŵj:[x }^O1bV6NKNc}Z+:c !$dHxVY7۰/$B~"gpa>ɿ?24wIDzN'c"ǂ_dΙcocfƄ}d MmQ ,iA>W)_FaucVǚ̻,3QìԍFc6&P^$YF /xW# QS Υc?Ow>.p&&\X<|$0b@N٧$F#P曅5{ e.Y+WC*ӱq~K:mItm&p׃͞z1Ѭ_Cd9*gB/ܘ3;eZOC S\v<<;: UG4& mPANd򱑜Gseׅ&2u`o`z  ً^3aZouqYK+wVX*7VM'0ȺhmJʯ-h+Taab1ɘRE0g{$ N?&3 +fJq?!:9mB1p"/0~ViôW'a!zY&0R,Ju_fqxm8}soqhy+?&:ތhu[K3$P +t]L@Zlo_ʢwBXI, Bu}MYO /5`i[P3(S֜MC9t=mED\p6)H?Y(\dCugDN5t(Au9 ӻ¥gXN$$?ɇ,U 2G,nG͠¸oF2 >KjH8W{P7͂>lQBa.Nn}oA3 1>携 F a4)0d.3'̈S i-.,6DwDcq*@fYiXx50Q…7.dpU+7b sdjƔ󮜗-D[E8s?لaڿd֘z LxnHpf>v>\ Z|;a .&%uw7*p89{W~Zr׆t+BrVy84!]֎ ^Zyz9%fi @<:hpKvFdO'ċaiB*LC9 4ylpp= 2[!໘_FrL2{E:_"밐%L,lFꭇaVp3ySv( ,oU@pϾ'kΞ G>R 40%F6UBg<}.$dIs3*6M P- Ue^9@s*Ι1 e@n'lEr=^SrYM'=4ivNxxycF!Yrz{2YA5 _U{dx29?f;p}8 _j4"{88XX <9IP5?F2SRX;էMSl])Tӭer<8M+|%I/ tY5%9Ȧ!Ic`=*OTiݬrY6f"沦5;ceZ$r (=CK8/I [gKwoM@˚Z 1]`-u^mvxY(o.MOfAr=5$9\KQWQ]!ݕ}"Ԉ^AΏ~k(pBm[wW CĜ+.A4XԘL]Dn/$D©kU{yZِi&E0 1ԭ#KѠIT)LV8QtYl]\I#h? 55SݲKP-3^J$A6H!>HI{~ӝd įFP@$*XlgFeD%$h7BT̃M'ն }TozAt9mʑR{jwc-WX.+P.[!<&Y wǍ}8bhDc6aO?R(so'E'({unX7Eex64sЬ w ߇e@:$T *ǧ-lJmݟ7KcͳcZ>.9"lR{ӐknIx*0q2H׬Waڤ WY #WQ3FNd!,iS[ S%ET}8Դ+ˍRFn0j'vy&FIrfLx(DB8(J9~SΉVPO@ uk hTF P(te;7w21x^?``};*,Cй=S |yFR⧞D#}1rCToÛW6pG"~։.+;82ns%ӟoة>#щ֛ #]B-TF\[ kםYJ/L:)۟~kB 3qЊ=ď]ޅjèRqD4\W_/ WQ +tAI|~(r[uar2dhU_<3U .gKsa} >9im ǦeSPl c;ļ䶬%DLUaR Pk_nGݚmv̗=9fô?8l;6\8n3灨@9~>U[y˅yy°Ǥ>h9GZ1=|AgLy#|Qxm5Am؋ZQy{1;Da&;K(֥|bAX3o >V[Kf{!gNg$/y*|{l9;n uݤd (2Tfl#e r^<R@D9<ܒpDqQM$(sV ́TCm4ԗ A}T즾*zFF oZв~R4X PqVpA\f8|ڢK0,x8rڊCCDTR=n6ĨrNV'? g^(?r`b,gC"Fؑߣ/NXJGf~ef\2wŝeU4EW.Ip s+e[gNE"(9 cW>Fu8,6c.C;1SsmԄ;p0QR ͙^n5^?Ycd53lkq/m`QA`wn:0IF+?;"$U<5u.y5 ~5$.N h*%( e+Dxr%σaX4@C.2{SÃ>T bIWǗZ=8ѕQ ;}~Zf4 LAo&kМMZH!IX#O_9YjrC3kG.npȗ-k@O/54vOOׅ* `)yoU|nTOgx~r^ӵYÀםS7uȚBũ; Sl#uq\v;'@`rhnQbz k<zΜC&L%³^;JtMڽ1Sn 禥σ/-ncy0YLOAAwN*G@YKaqӐR7>MWF~RtO:,4)9˱+Nd/ߡ5#ϖY$a_,Q?뉔!̄PTw&\!ʍةlș\puԬkXI b*Xg4ccb۟尞͏lm}Bne)l ' 4n 7u,P2#N|jv+E<7cQ#mZ(X_]o9!S*S[r事q~ɧΛY;'I_ɎDM5(#\'Ot!wRb" /eKKWr%jcH磴߻&'xׁ%[,&#פ|D9<-EE[ǝں FUa2?{|%j3rQQ_T^WA7*&EHˑv6kpV|֠V|kc?av&Et=$u٨44 *+zcvfkp` ͐1)RksQcsλ̅=Ó.{K4:, ?Hql^raA1=sc QT9,10"`0CT(ƣ|;SC"׉LΎyW!^a!-4Z&#O)ָ 2Z߅ا O5;tδg)[*/Ɍ &#@(6DR$I4M6 g0Nmu E~ET Z;:g{,pgPG8P{~psBʫKˠ#у$:sO, 4 4{`#|qU-<(~փ.v5"vR'\j9XLqQz C)/Ӱ R, B LU2K{4Y=Ӥ#KK;\aģzg?w^]C9^??6LK~Cll*}-S}*_qEYD鰋XYwX 4hfxd+v3Y8!Sf0BSa ^iZ#oiR7dCǛ%U ޛ#1~zヷV/Ho w28Ĺ2[둕7G9P? (⛅z$Bief*->Ji܄ BbvJKTU>|Qa&0sj )NU-balfȲfMW4UlѭJ.x(Z15ߏJl9\Po1bւ=mXzٲne{=,kn֫'3kKahY O^:n !4)EE]wwŖOv)Z  o&^sRJf$MNxqG0xШH@1є_4&#F7Lڰ߷*tG[O\54lB!4GO,s)ofuV0 GeM%-/e4+JMjw Ž*%G.A_zq'ef k Fz6-3Y9 %, Љf&hHG9tivY%bᵜY~L]UԒ{hBPЋHw. iㄙ 5,AGӸt ge>؍*#ī63<;"?ؕkfZ~@z\ٕg4MFǭEj 3Si$: #B`XcLfAKAWfV~-z^ b]Iヘ9EdZ6\nN+4SL"ЛJAc^#EXa`MnǠc#\FW (gݹZ[ƺI4ߧ?k^s`^&=ypD7Al8ϲ~tt- / ڠ$yH?<٫ ]md*_LDnJ}Jk>UCX̪h|~/-)|>[1Ek02Iz/S`#ؖ߃ڧKln&7&Q2yT^S=d_AˑhMEyL^ RWiuYv] B8=zrV.s\FM 43K HLm̡̫Pm- "S`+ZG`hW|sáГfl~)&fpҖπF۟3,f~`hDy'@cuޛK$"DX8cF]AE6YViF:GͬXh/_gGQ~qSnՇ}ox{OŁp؂,:rh.)̪8fracf.< f%ɯug%FAQJ B^͊J~9'Z;\!)Q(k[eQ j 2܆ wW ӯG%,){pgWf4wq鵿Ș zv#S-]nLko^/LnC{Rw:d| eovmH_?pRh1ʚ#z/|3'}AOw1"@2%}H~` PUGy&60|m;3&d`kDtZ;275f;A4Eڑ`aF~է_!{cq1Q%\F r!钓 7fWQaL2+f~x{'8*nYRmt05x`P z0RpɬJS`-p៛r(1%8-kEBVQ1ږc-&,PpBl*2IQO!g?cH0{珪At!L# 'E):cÑhGDr8m[y+nHNwRGd1J  -(Dfu V Xx}Y=,.?Ùq:9w%^Z.g$>yضMR0d(y+8>VBx 6z <䔂)ב5i - dd7aXO`}+I\+O5/槊fxQSOP 23HmM݁]Ȥ%~¨}d!7 *D{`>##Y^d [r`BJji:_NOmŬrU'9Y]¦B!xQšZQ /EYYK_c9Hn5r*3> j*. 6]%Btdad8?1II0͙#krB.U݉1[$>m{"ShKRB$h(\XJ ,䑢Q}ݢ; N>c[ep{KSmr<#~QRQCޛKHØV4f!\~)xZa |dlBкCFqŃ2Vl .5N[~xJ3a".6ڷ9ɐ6Ɠ`ph2 SE:vGḗϙfG,gm)Iw<,xx]Mn" -:Z*!0Țu0$uƒ.#-7?37U~ qf1]1J@U'GD:xֆ%y&cƥ xH, nnΧ!b~F6RnnVsvЕ Sn94;RT2&a\H^ WWzD ۖ4>h|yIqG<>*Q3!b g\W\Y~Dlp-–Օ8`FN]Obo9 ~э5C{!i)Iѓr -d"CjE^&:F\X3j{! YٍG2t[ڣi:?g,o1^/ʹېpwluKJr{C;f;_/ Zs@b gPMi+鹽^!sHPzpa_ ܃8]!vL[u*Y374.dSp&*ɇYf3t1g"E` }$ N|:=.L*6Cѧ'{gގ[kCv~cͣ`+kR@?nGa6M#TQxAR9/`}S?w93BV6t-픢crL2g7$;-{2eQ/.|Һo)z,9j#3& vd3V*{)*k]C$nԛL:n ȂC_˯ EzSՃp/ #r$ Ms~"0 ?A]fh':h҄dE3s,Wqt/ Hr.m9pU'&Sc?Ȕ1HbLg׹i}GOu`eG̔ ڠ[{:TS! >g[{r ՘x`~1׭O,7i6 —AJ۷nJYu #Kim߻-*()eSRH$b; Aw Xwce%7`w':O Ԥt7J5oDA*TCbM<Ǒ6jT?+BwlYCp:ET5V8%亹ܦv 0wZb)(w6ZATvը(aoR$Dr@)ʵ&]W7CK9ʂdŌ:ԓຬl^fMŶZG-A6Y\S e7[\LܬF)byLf(\@=v"BsJBQw0 q+wq\yZ]kS?E9+ȝ@]|2B)b&}ކrn&O^eIǏ8Nɲ^9Aζ.6;&$rթmr<Y>ҿa3ZaV'2ͯVT Ayd' фإ&y4YE%&XNoRuxyR.{~,|5+aRy"mC’HKߌhgbSp^=g$N .χ䑈L @NEx_x8*|ж5 Z1l-}Ɂ@̛FORᦆ.v扊ud1N22ڵ?{xIy*Cլ!IYmnځ|3Bv6V.5QM9/N_ZOceKzƮߕu*_@an,LJwO0WdjDb<\3iyˤK<ՀTܐEX",qeA!/r 1Ѫֈ5kG3 djy&wԗVP}+b}i ^6VLH7=p S4˨>M"M)ǴMJ*qCӬ%P3 NM66Jta{vVx=?0pʮK@Z&_jJAp7uOa-eY 5@~Rކ,Br/ٕj{>BQo4釕hE{'1)~'%^FUplhZ[#lմ&qDcW|C׍>9`?Nl莛"Z0d^K8dIĨ3u5ye؜Π9*h|Ү}Կ?% XES仲}Gw6#VJ& Gԁd + CgLz-|2,Rك(/&SS;<.;%yẂR?he*=1$&a@OȽ- u0?%d S1 #]Roq!HYAB(C)eE;aV9EB*@1*⏅unA4PþUk5+m-ږWf(cit?)`~&gg#]Q-gBv2=BYdy%؞3G[܏ fD܉r'q̈Ü9Axsa}pbB'q9; j?[X] =rNY=4uh@/ ti83qzjNpdr;X'D[w ʼVc?9m)/q%|d~8 BQzFHluG;=KչAU {BeGlðW2f'.3{f{w더UIc ǐ,ꋪO|a3<]C*ckʘaIwyBny1?  \1Mgi.XNM % TTx Q8#݈N6*Z^׭ #!FwA1q1|ʉꧾK%/.tٌzx᷂MN7,|B猝[{T}=$=GDMM[ @F90$6(*L;E}&[t& + 9DvFx#'fNwX6f?Us8$&?fδP֋s11f~h\F~~<ߓf ?fdzR{ ̑..N1grsMӱ`ho1ۆX߭Vx1bYk?p ^X ;T`q hr[o?/U佪&@JL024ı5}O$+CΡ4@`(%>'*%ҹBkxBhW)au: [k{FP+q&1#͵ Bk4]It}\MJurP;3M|H$0 SS $;a%[H"m)™\HQ @U7݃t$6I&7;}mUΓh[\|HXl$@$@>w {d\D./]E->ϋ}/ԚҞׄ,jڊ(N#PQc3AaZwg,]!wS;Co2@1 }JC mRa/^~4v05F>]} kpJW>5Sl6it=ru?:ll$ ի5ɵ=A/=u={"az(cHUiVR#zgQ"BY wTß!~M7^%d+/Zpiݯ՗fq(Ne\ѨoPbQoyA؅K4C2J O`E = z c5W|6v'A4sȸ̻2 { !vwSa/+.LOUr׷e4/K$p,H\g,] _|}Փ`s=9?`~iv?Xe%'8p~۵i@<٘|"ƿ>S+(μ=/_[wXc YE&1š[$&tac|`.> " [Eq$\0Q" H~T:`#3! wj}B*;F}*`T~b~sV/ROk_b/޵JׅNص$3j1\]5~@p1( 4r14 Jyw&o1L-Z:_G'@Z{ЗF۵aT+qNotkhm.J-!<:IOb%F/m0`(ץsz\)Ohl TP.ݣv6oV?%ؗt>)NNĒ}9ړ%'s;J$;g݂U,^6Xg3FmjQS #U@U86S>dO:5]#Zo;Q&eyb$^šϰgG:/`f{*͹~=!^Ą@( #3Q֤%mrHA0D9,Gz rFzcBWmӒGǁ7=II)jQAclVB7dz1 b#c=ޢԛzFtZ@7D/!)AcJ-XI&L\!u!hQeZ,fUGT ,#V&66pЬd,^AO&Hsi$4rT0](_Z!S +;ZNҋ^jBWSJk/bíЏ|VH8=㼃 sa-@ W-GCtZB/>@aK`yz-_}~ص°7`mB(zÔ23ƶ_)cݓc'C~|A\A)V ZW"@|Hv۩&atE\shGˆ9Qpixlv)2 nqj zC'fNZVx@;6dZ1у7 R'dByRepN7;p`<%0hnCX/?gxL3ħ`~&|C i1)-!sm˾R=;卑>s! 2A(۬бH!1= -j(SMvÍMͩ;=2$ׂI4'n!W9Ϙ+n%[w/bk <?Cd^ʓWS]: ƹZN1/+̏!7"NCd,9Bo|Ը* _eVv'$SzNV!.uWW/XB8pq[yk@&Wi:ht䮽v*x ^$Y%Xoc -mn,MWUH@O4rFNRg(- !#q--~P2/;>8G0qSB=ix)_gͮ]rs1٨P3Q>ϥGa_q4,MǙx= 4/K{J} k( ns: qHdDCX{\aڱA|>wpq@Wz u޻haj$D._b9 8b\np\5FH"Mc$|6>Bjde0pHŒ_xlIs.Cy}ϚRSأQHh_oȪVZnoOJ>mSZ6xYǠ}6b}K)9L>Eg"{hISvyiq<0F8BsZJt8 N;{ U45]< :KNý߭ CWPԽRz'Ā@fN~̃]qYPr'u{V#x" O}454OPIK]g9>NӷGY6c@+9Y}V]:4H9:c6!8a^0_lL- P5_/W?d/O2PYk*Jcj⽶xa`1"hp0-yu\w3/맙x/zyU(/ ʕN!|h`zIn[+G-Mӫv:|ԢdnRCJstSnyiv$n#`^3K.ȍ߅Vj_\L+NR2 IB2zǼe29CML?!4P!&-gMу{:7[mUq@$]- /\TnokVOMzj'I6Nqq[7ԆW[eI^~R1㛦DdPMٖq͟SZq^r1ֳ#!F)4$0C>]:-f40v>ۗ'd1:"{ʰN 3T8\2I heռ_Wk}xW%MT\Id,z%<>J3x2~f_sRMf$N_2nU6Z}V+96șd}58'{>E-%K}oG]xr ?Y{Mq@Oq@g0s ,$K6;Q,gX]̂Q08^_?ZbRġen`'yLḉ*9ԡCԂ/Gf@K [oWȀla4[Pْ"jtf7% WhL`Y ))1J a^7_ цs"u<yYЧ"9E'n7,PHZMwbh@ `㡓&fACoE 4'͗o{S$#裤bŢlnncl[xfOtL1Z_g+ (Rfqp^{&x5_e#.𶧀:[UGFH0:?CS%0n˸f=ƼƝuAzTȀ'&2?'t@;SV=)~~d()%C,K(^Nr%H+5ؓr o֕!ȨQU!!9֬zrHHA@ Q"Ck_!ȼa9W|'a:1oɧ;IgG5SV8\pZ>K-&_K:KҫJxyyZ?*=à)Zr|D_"RL7!U7'qr yc8 ane\hf5l5K.tIP, ; J/NhH#$ *}R?3,5b5G~#ER|g6/PS"8,[u?^O\NxB8 rND4&a٭63gx@|R|\<ȨR^v-h: ZŒ7$U&*;cOfVE U#| aexCIV~4/\1ѨpØKqQ [q]U!MA,Pv"RRZ-R Sj`t>T#mJM|4ǵ/ :j88ȈMwm2PMh{̛aQʝ;%2]/j AUr}7;t +$J4nxeVГD+_V;WM ^<^וWf x&%+ #WnDOgr=c ~kg gT*WK{48t||s.5Q\?8AǶn1"=~`R|Kh^#ϛ^пA5BnID@ќ'F9Zqh v;%`kT&&(6X 8)W(kIT3(1ͩP?Eu;akz</}h9X P w1DXa6sƋ2&:0{i Y&\0DGcOlq $"kDY2X! (nӌ3Eжfc.t,pnW/QMenj s5`Cm{G-ehAPLē>SR²*F{^He;5V>j~vYŽ8ԕc +D ~l,8b0Bߊ5ܐ-:mf@b?5HSĆQ:)?($10A8;YSiH$ <%xq0.BBf1J;kYK+e8I1pq#juaYA̹3r_X{nv E wXuo'tm@[ڢ5F0ϛSKZ7"űcEO`ʘK^c2n@WK#m=a/0'oGpɹ.ADv68)'Kȶۙu=+aJ9IoY렛:m¨@gi?>~.?i 'ؠ7sN,jCH1 s]<`޴}r_qF@vwB"xiYCh OȅldjYAESeg~44 Fo E$1O(ՋM0DD~,sRA'B>Bzo\vRe-!//ͻ2Xg%+] m@b6]z'k+{nM蔊}׏칿ޮ:o%NQtGx~nR/IqrzD(,`*Mly@\rUi')x+ 7G'/Ypwp$J.z}D?xf`~{Rc<Ⱦ.CSÆ$H% mAJB )VH{t ѴayIvQdyZzjED=%BM_U=iϗ ;hiH}PM76z߿ha^{-mTXM>ŵ<(,dsEɢVwę=-4_s{#F N]0ݰ^(:@6  `=ZWaAԚ,⟓< I8%Sry j?mvk2O5<I(,(xuΩ/:+7aL/^;G44>f5Y;S%z:&)bzq[*8*kKSebŠɹX#aNalkN"2c4dB!%W5tv=j鋝..e8ؙrM-9ܮPFAq,_rx<DۏMq;QlAۓz> /$}$w׈ݟL8 |x#11QOb *7(}t3tNEa)߃; 䓒8WDj cuzb}%@ܔ HO,'ݪDŽҗI+9Ѱ"\;z->wۙv7㩟 hw˵En0~"oEق)̙'soIUSGޭ76<X_cX!w5$g+&HLR{b@3m@1"'Q7=:g(,ogC׬wY#l[d_p-2.K?#YڛhH;T51+Ԙ؝B!)ugbL*/are]B p$< K %-~ҳk2ֵ rQ ~Iʲ*8;#Gj$@77ZL*טu | xdŸe]hHC]r .Mr;jv0y+J{3-ᶤZݽX"rfm L}qe90nY5fznzcE$1a~+.lB/ `|Wt9+>-%oC'JG h\hfXZ$i$>i|.|"aSѮo @AeϹ$؛@_Fׄ˼I9$U(M4 4š§?Z!=쐘 Q5g׎knk?,,#㨽t$ZV 4FN0%AmQj08OkVGbe<_tF:Gy"~{&*hLK"eto O#. ]n6$_7X:pFvf-R-Z4^! fٶ#d`VX#BfrkcB2'^Ky%,L(U*TG^2#wPл3g>yGԞ1N Ldmj>sɺeB_!Ay^Sv=EgI:af/ } [\@"NuvfmRȲÇn;'&1M‚/kw9-sˌJT7ӷr=VS;a7Xm[D:D(0a|[JcP7ư馒 k τ:rSWf*BOT0%]] '(kP.Ltrߥ I>igcPnpNn|*$%ŏ`l*ve9S' Ke!( JpHȋPqȺ^ķjDѐ}xB^hCڣDTA#uj)T==||CU=MGH5µ 3Loߖ6sQdɆ ty&\9Vx%OʕFXI`?dɲeakVkSןb_{SV^ GȎGbPKZGd CIWW-QӨJyJqmd݋}J++%z%C,iQ4d82VKaPHsQ  9[X`Hϵ^Ykb)ؚ`{-ܶYEnKvE$`ɒiӿZR4[*qr\%d.!84<޽BmuծUv.F7,A0%8[(hJ[5%g%gW@K`FZ&AqA\V*Nջ|48.eN]9B׬'ڝY&7` iK.#tH(v&98Ê n`Gub92cnXD#1So{ς$1 n(<8!:۝V&GnBNS"^N!;k =vl/6F^^n"rq@dS!!R)54[qt@I &d^Eh˟. AGHl>+Jn:)M.W!&S 0kjEm[(VnEkY njE{IY5ӚD&1:AK̏8ii6c퐕ú˗\jˈxkZ辶5-Ko-!\x.BVc2UZbj*J8h`FiL?]4PtqlFVD/I愫b399ckbOPC%ˉ媿]tQ&_>]#QM l_t d`mƙ#5xkڦ-zq҂#y@VNR戉,.tre@:p vP!`:&`Ep0T-YIGJ/qt\U7EtɀE=OQ$vS"ECǨO-me9۽WE5ubhĭ;ɑ;5 p99}ZqfKcXc i;LJa z3 `[-mb L#SLzk#J÷Zixoa2Vn&ROH+Bj(>e;jE*$;Eҿn.Xnd%*E럹CeF(L#w[ 5?*-~6Nee 96up=+sd\#I0Z;^n(vPpKhn_s$[])ĢY71?r.7qﺿG"wս Lo67߅}? ǡ"l0^5>Wz`L.%"k.KrW”'_s^l$+ vOY@Qpmjr99 v3JϢl2;wr֠EMh n;Oo`<-J=orN 70@ֹJZV0so,]~s'˦PZO;G&"IajR[c^b5hL-3g5ACQWhU<*ւwX`$~K2Y#L*ϴɂuK˚~5_}K؇uƼk#*8G̽-s !;h+߿pMdO1!KR^L΢У(NUu+RsG0'7"|`Gs> @o~Wt-fXpt[eL޷" s镖vWVE'`CT/>aNNf*mpUrtfO<# #:YWξWeQ;.W\#IiS'BTlfd\y|/vn"(x)1#).,"%4$#Ԟw>7PJ`6_ "f$5T +ȼPzYGKysG1TBӵ0SK V7o08s,15&fkRz-zi+yP}Au"2Tz55J-slVy߿W~=A$mD)5Sf \?U۫Yܦ _״!D)bFnJ$O @8#HB1vB"v)VB˙ݷ{xY1<\}qmDXϖKo8[%( Um +ω(Zd ـ:#fj06rymұrl5# o\'. =$0Zc0?P8)7;\aU ȯJxX쓄*'Vx/|@ܪ%$YQ]^| t;t,9c!]\s3箍Y0f:nG%AQb*tw)&FY=[}ns/~U=;+IODãN,#cA>yɥdǨן$mr4 yjŋԮ2-wf Y^ j@~WOm |A@Cq8yd#H.b.9_Ë.2~ ZEnm򁞰2o 7b׵Ex0̈H! aQP`'6kwS^(n=IR Af6 e()!:#RFp?1xʧ&8ALw!ӋP*De^7wؒ) "fXgTNy[{0c8.$ th"ZHamKs. l$3`I ;mQFOc>ݲWB+4iPt9MiA`dlQ֜BѴV8zR,5SĿc`d=%Hwhq;7%֣C&D2sEÜv_fZ _ '=._s$Iszo]x~M(#{M]}"z(B5p]sg|  D.2HdTe2C"U}Nb0aZn^h9%U5Vf)hr')ۢx:{zxmp eE`~-Gݞ<'>: 9FsVb01]l.//R[r6CpOe[*Q<~_L!>`¤K#hFsGdhG(z3of(,PK*{O]y;]->XcZ1 {^Jl=$p7ZʦeU1UyLZ-d[g2\Vq4]teOuk!e4WgJS/,{/d@\O*qƠ'=V8V[M"&nb.a;&$_Dc5"$ 6&Xd~mnoEy$Tγ\A+O1ar¹n*MOtD lxXŋ5Yqv7d% Kz(k9*d"S6&]Z u0JcUGf)Ӂ)ȊXVgXо5ҙڥ/2_tflI>p CqѳscAcbV^5yE?UWč`|ޢF[lE? [ퟻ|l6@BQ {fp8f7t#]B j`m & TJaI$1e'>REªh }K]аa^C(f2ll(:Y;Cn^ X*4{ ~8VxR@Jˀ 'Q#&M&3g܅]@TI jdk (N3IΜ7ȶIN{G^m g:^?v{Uߪ?KS#_&59/cݹ>V>m]:b/l& Kh gq.׌($߬~:=2G{I#ltH! MIwu\E9"FM3zQdzYǥ#'[RJ̫ŗ24`Cح 8*\g,ص 2o8K soYSMoNLd0)SH/]7Y 6炌ı3 %BP 2ڡW( / zfmWc-c8F=^H`>B$!_MYR^#d{_5d'd'bf жю0^gW{S0Zv06D&4\80T4XCIoؑvlvKOS2nkӹܐL V7G/'1 *fBidp Yq~&ZfcmW0XL[O NүwVM 9nC2BRhGEgT3>6P3} 7!;z%cK::5"ߩ @>RCl=XSEV}NkNXTJ rn.@,Ҷ&_H"u8pil ].#ޅ-֧R2Jwţ,oVHrƝ|\ԉE >@_)Q8ch#ͷ,]F  ZKea[z P`]{wT0݄f`AN?ݷh*cڌ%tA;Ե= %v"4)r^UqjNeͯF7P@̸;RKάcgp[i(-'6֐ZZЂk):g9p7S =¤(~'gdV< :S6@ScRr:U$fc4IePq@` uOzaS6JQA2^NA{qAЧaL\>)̈́BZg8*{v.djgQ7uKBB;wӧq/X`Bi^!S@y2MF )8gv3` EE@Mm\CzP#j k(Λeb(ݞQer%_!C\z-Z\ty(j&aܒ!]j=IMKi0@Os4cC0nF v 0 +7t7 oh4e' .gr0ycE\ui1|dW /߸ (d?7aӒPKZ5Qzφ(}c9ҿOȀ{>2Ds۠$,?t/͑= ךhuQ"FUʼF (}J0CۘzAuZ~*\nrt]RG^ZJq ohk_NkXe74һ>z%q쫡(i .B6U!!Aj(ƪ.2AL0ɞ<)ډ. /S%2Քkpz0{iIgҀe:7Ҝ:!%zWL$ ^T1{i.~nb5 FU&b z+2E L5RRwt޾%Wuڑ:j\ZI?&M6s8 8YARiW,pv1tA#Jexϳ,D4uqtKp|/Rk FP30b drerisSN;lg.[UfW}[쏓Gʓ7d)ǿsqgmb|W4!&-`ڒDI6ZYf7FDeP|z{äUm;Hw‹&^5蓓T؊Ⱥ3a_22Ыk\$զz A-lHP)NKg#1_!ЁX >jr$YU]/dn? A .1AVTVDc =8Vpc.űCTP,K#hqPgLT"̴B@“O*Gݑ(.zOyտ40T=Lד!?qP ?" iV[{j;bx/b#w''igMgM3K8{ъaO$ZB7q(':pgGQ o!Fo6oi@bfed h: `nr_c/DWiJqzEdw jLF+ ‚iT|!&+!B xVA!b3;^ƾ"3] 9Dssu]Hgz6І( h8 3HU ]fw))^YzbX.5/d(S'!4LW]߼{Iߤ 6 9Cܑƶ?^k ^@DyS04O}Ó4ؘCWg,c5AOt1=&S`cfNF/D eI>G=&;&4y|34`Ҟ,LNP;7mG@1|:#b3ZŔ,S4h8>$?^h߶P*U9n>@&Bo0\0/ӡR0b1Dai#Crn~Z{Plu#wIz7?`΍Xؖ>kw]*^@8? oL?9qj`^]wt9̌GżkR+}JBf7&.aҹ"E:LhXZ#e1&H{^Dh>KH :=pYЁ\Pkԇ6)X @ =1#K--mk*]l+0RL׏^23 "¨B`5O CG|[g|\ A* by)ȼl5z4TMSeA d &J[; EX9 gT]p JĶYR_!'=zr3K u_ ߜt 0_u޸DΰT~ï w=!i*IT\Iz1|g!Ui}biвG?VfyLbvDZĤ J 1"$N 1 lZ$v.Ӌ֎w :ѪFPIP?@2e9eyF kg/ 2if#)w";C11PdL,!ЃRZm)2=Sի/teetoB%naBcJ}y~''gEOn`LV<lB KcVGmF -gn##V dr^{&ֆ[cepJޯY/ Fx!ڒ&iU|^Jjن"{qykg_b Yg.O-Dr|L(ٵ뿬qTN)jho'澩Fz?n%m96Qu~Ú}rpӒ~+=FɊ/4*''|' Y9 yCX Ydv (S'd˅dim@*m $MLo3:dBHO֥G|{wX0m=qKUxGd4tpsHgqw 9Wv:v_]> ʐs1>;-[ uϬ4sư3>EJ/v\¡er7u6 ^뒔Q!huoyt5d_v($V?1vҊ-~)3Ha}}4%2zWR;*>ޗ9 8m1ߡZV:xC)$.o"hV0.O1PEMTPPv=mlB5`h ?2LAjcuEDڪe5;NmTe$h,0 o4c4+?R\ʪ[ǎ7ɮP)|s]فPO T^Aa,@Şw>I%B@*/̴ںHq)VpF8ALǁ^Gۇv,b;* q)6# db^WJS޿‚ |QBHo(ƜΏb;)Z=|v+9: 'y5dx_GO -(@Qtcp.uvOs%}eAm S̗JHcE/#b]1aXR\x0ƏL B<'.qi[M,Ͳb!ޚ/l ')  Cf/AM'oKF.<9P]6aNUKUړ w 2dM]E+,5f&{=[Us_Y."a®h%E)ꭣ) 0 e!ND<(T>6|#4ξQ(ֲg39>M!;va?~GtvC4jpv5,_D<5!o(y%$Cpy3AmT&0َTkOݘ%FݮUuK"n+ סkGxnCF)SxKYp[]@ùĻ+>C<\9'M$<./NCy00<6dD&@K2"@en)d7kR68[^!{n=MŸkN{)$@l2/Vp^&o5@TExh+sI sz[JK-M8WJ:N}Pz#y _K`SSg)` E9/*L.BI,ak&Y_F=.:q#ѓoh@]ByWڳ1F2ϵG Vkب%Elk{X8qy[;Y-W5ivKX7;r9&%U*d븙7)h^،&alzoe}f+ٙg{+VH/N ;xm nFVWGhdOFNDA@?Utt)t[17M=5>n8S'Ÿ!BZ Kd:ȣK2fث[efYi;޺< e5x]#+&K.} /X򎖭)`&W Md.Q f> v ;IǦ >dQ9گMa م"0qHhwB]cz ?A:[S_Okcêf$(4W7u[?eCxJ GbM9:c(]$}?uqO.e$`j #&W3_X$6EٚvD׳ /f=b<-y>9Lm|¸I] Fs#.s܇e\Ŋ%op* 4 l]Wڭv 꽋]W<'j!43-|qDEDcThi4s#j5K uc@j,tҁD&g\U4*j?R#'i9ToGM巗*9DcmCM\dNe\]Lvz}d˭0AUI{ڞ&^kֿ ZE5 z208/$W< i؞_H;=jґaNQfq- >Pb Xlg8k_~!?*8+[/UZݕc41.)Vb梞VS ݇ߩ:\ʰ9: 4.lOҐN\_,S ArUuv_K#;zbϢvVÕ (2W&H<](?_h)v 5~%$+tŠyƋy',<+Ů?V7j{pKuR`꟪QN]x$|LƩrHQ %%M sio##vj5S"|1Ѡ\h?JXN1#t'WXyx֐u`ECmW%,*:uK0TaFj,nh§ֱ8;s >"tiG nI$P֡a 66B;ۯ |MfS9:TޤBT<{w`u|׫p C.cY`P~0HcLۆaBǔEd$ 'ߏI,|$Y=-{FY"*d$u(O}oLtt$>k&wH\ZcuoK/R9/ ,z)tj2$(=ZQ]u}bPxm X'߆kә#*u:#[;!i%@`G;FMxSU䰛GAzC}ZZfڔlf6k^"\uu+Klϒ6m!Ԉ;7%t.Cl8J(&"/J[07gpaPeK-EBW}H4B~ҡ0I%!D)12ϟ_8YUӵcyUz-V3Oe੷J5,B$ .a@!fC@c?lr91N4fbbǷz7{{3{PhssĮJZ*/k~f348.h".ᢖ=9re1R#!ћբm!J *lNPu(,ባ2hR7f VQw 2& cڧau ODY Ǵ/qm3*M2@0qT~0d5*X6H2m>8 U0|ǰ"w)CoQ Seƫ~ɨ |WrRXp8q"<]lR6!`4%M*># os#YEŖup膌RHys AGHG B3A]c_My"Ad=h&AhtKOvG[_ @b%%pMz&E(Ey'/bMZw',)ba=L o>Zsρa6|DGǖZZ#$^p$0 / f BȮd`{yO-rhV%A줣_υ ? xfwClү3$X3 kFWv,1 C98(X+?`,il~'?m&h@<9YLJj~Q@yͥ!4+\v~w1C{+!bʱYjMX)Ԅ: ctZ\2.?2TAI*]h]} s>XyMҫ &A8e4ԇY%qbw1N9C1X\cBv9 #Hh?H>q~BCi"I 2Bw2I?B-#AG'6>ǿ%(tfS#LDNjY*F=g׏S@>ʕfqo!\1$#KSz#-;̒yjg]Ҡ\P ߅΄])9 ^>cF6oMŞSjz6-tz\utׇvUs_G`R6kR'-C=irI%0{$w!Ȼۍ}kH^8DO&&eρؾiM^ՏIs9F@EgඃeERZd}Zy,._FӠ_oochdVS- mTF 9cgz6H@AfKsҘG1rk6Bpzgʂg=ڥ]Ծ*=\e#RI-hR͛d%4bJvsFF"hM9[9Lˬ/T>mZ-'у,ɉV{81~'@q_RFu z״ڱ_hvzܨ,GFj`bӹ/Ewcw #~ϘW+^:%2E, 踴!E@aC󻵢o)xY)71NvZF>cHRSq9܄ԡ;p|n |*VWe<A#=[7LT%AnJg4|xc)RLl5yc`z#;Hnn)AYn? pa/ǡ.-Km *Q"z"&vi΋5/F}Nd,u@2`=ըݓ8E&^~R4`. v{,Y-!}ci$"K+`BgW2K![`Wv \)вrqD*j<PՌpNU4"YE6'Jn7}3?/ӊ'DS _&`rj.Զj]ZߘDFc="v) :p>v򐝇d EƇ{L/9?CIFɨ|^lْa6:>/՜h̼zܢXC|v`m^X3y `5}?16'mXnlaEFD? {DnX޶X=ѽ@l7ZD׺*Y- CfzX6PQ:3:ch!K-쨄Sh~D>Sp* ֣kxJ6;gG] Db(e2>؆Ӳ>|4ɥrbU#|_fzt qpu#HøeRT~R#wn3an#6x4npzη /Koqʖ`/ *8kz+ #EuI:v~+D `S ufy烦rb)p,S(g\'.'`>9{*>Д RاGV캲80_mQ?diRj\Ϭl,nʃY;ܣAowb#o|zN*IHVT̝S*T'[w^NySu1[5-y C+D ϻ/UxP 'mj1 '"t9WGO֠Yjg&mmdO}6MSM +Uн-|$jDgӢCW, ǐ+i%f. Is$K❋3e Yuh9!Rg_ڔl]>hM9Muu>apFʕ31P./(zҧ0V|TbΆ3dP}7H1M.lN 3Q6|Ԩ80+G훽^L"Ch#DקFGGmGout(C_0^ǜGo 6c g?w p!Q5y e;J3&=6NHeoU4!דc0X*5y -W۟]Ujt z쮷z ݉E\.T ;cti4>@w y9K''\2ψSEj֓Sl='-"B8s ;wGo79?#gs9jA5mz\ځui" vࠤ3-(}{-/&Ћ%WW+Yw~eG9%`tdݼJ'@jO]1 RqƒDm(. 8hMyhn[ 兿'm6~4X',-6LҔ[f&E)@"́,uNb<쀒EA)6<4luK'Q֧Ev@S)m/"H9OqeO`݁zdNssų2ԩ11.zv&;{ѽ<}Ȃ Ț}!|V.q_XUV|> L1NV>*ࠥƜ|uvۜL&3,ptQLPdH<&JN%u6EesњKa9~^ƇȼP}g ޗczֹBQ}G>{NAaQ3r@.@ีgo<ΤÆoK}UnGЧU,QٽOe KUD6ۿ^;/F.77SZX XI]<2[hUMO1xr|: ~ qO~` (В=*[bcM,T$qZA:/('mӮ_9 "i^ eŖq(8k/4%­T 6Kuu< -?Ș:]c]FR* &Qm΄v[%j:N*cd]zpsgw{'jqMZ O:-0y&zZi $?̶PO$ 7T eQ )wlM ;t)L)oD~bKAW)1BBR$Vw}XRBL5ɺhXVI-pORxJȞ Ge` I"=0jь;_έf>+r-7چu2ޙaݢְtooqv6rk;ް(dptw&m*8OEwO@L'4(㑠\9x{ZJBH d>OQe:W>.<fc6.B&iOX;/fhC}djXTZRV0E$VmNE~93fO@D cCHi@"c}b6Hүq7 tpwRdU󮡵aM' o-;ZY12#_6]8ғK3`R qZ8iB(sCw :FI!Li,yk*F@_2ypvOrHu <ʀP SAA' z=x&-Oe5\Ebjrxhhbذ+I }썉`|#]RQ|*qW~H';cgxa!h,W^Qvw aRKDrKXvT`u FÏE J_ho{ `P|7Iu7acXZQ|\‚? K.; .]H]<k`dq "Ҙ/=Vf" ~BG%:&Et^ ]@3{ki.tr[ۺ}MEf5L>=I<@*g{IOxƼL:P'̙9\V P˭;4aKN!f7=qZɈn$^TΪV.|Z x ߼:|i/COvecF#-Ѻ_D|gTϭj(0 uz*z?Y֕A Y;rE==c4u}a|Z߳ o/\1C1gA ge)&wf (5#cDx앺@u?ҥx53Bbgⱓ 3:<\&pruaJ5ͧS&[jeX-b= 5X_うÅZ4teFΝvK̎MA%ϒl!y!N'ۘވ/D#G/62z|YS_)IMo+,UbS+^eIU)}QӜ(1[bŢ4QRN3πwYI Lفn!~}Gx'dj tDP>AyӲ* Gn#S[3~F-@N{vRFZzbnjol!r.K„E(x#BS[E%ģNb/<4a0dlj^;6dbZ]|X'}_m%A\ =_WbЁ 0U@(q˄vd C{h 2@^F\1~,W6B8䞫n,wQI(ڋ4-$?ػ{5s.3=`ZGg{!{|kl[8T -6E?g$@[>2랤YzQrx#EJlz0Iקz-?r{j,D0Y  S+~  Jznh b1ٳ,T1 !F/ЁvH?ugZlshgmn!VWJp`\qU?v*=o˱)r:?`: XQO2S8@eLP?㇆NMG+[ ȡ;djx'x#A25/.. lB L$tD8j۟ Џ8p7 ^~IJdA(~# aF/A^PA_"A [4po`jn=5[JO#OK3(uxX gxScw tdLwvxx3^%Fn I8W`:D@DMkL"f6Td5Rei&S7ڥƮ4Zau3YȕDFUw"{=>ZVo[*.ݩ%*Rw)^3600f[]&'u#ܐ0oY|(z:Nq6fP9H6aXyakh,zE *g~ 1q΄ץ Zny5yԙ) gOg$WO!9Fe8[I}K#y8494^d`D{KKAo,vhrg.iEN8@j}i╄`Fi哅نroK̹,mw0)8 @S|]‰RWpsMk냑`ݴuJxF;[Q0 bBFsgϡֹ: ,;%> b:`뚿q|؈Věg6I nSW@q,$(NI֢އ'o wInR P3Jvd/lMH~bm}3]MUd!977{Bkh#q޷D@QC?TGzOTC"-*#Azb{s2'ouq/7 B-<VFE`.3שO/&xY.£x޷h3gH;(I{JR$F-.m1l*zP^Gʻ0'+<DPIߝoSnݶO3Α=cC ޥ[˹AȃUBԂ]om^_YpСzM&yo 5cm+G?8͒BKk;@LhEPY2/$hCK?pj;;Rf^b:hW"=ltB]ag\-C(CX\ߩG2b? i6H[#spGؚ3园Ֆfe`:}]"La Z(!(_qSZV>38i6rD1 ~WUfĊ~p|tMϟ!<#OGbLQт o[-բ+amv+?*mbLFL̚yEy߄N8-$鿇.Oay7$hB.7f-?s0!.u)AYFR63X"<f*JPDw{% MAU1H_{C݊Y7+3HÜ@RulأMËɡN` uSo΂Cg'eGBC0CRo  Vh[>I9@ ##ͨ +QkU&D R餅|biPJEw\+*ӦuȰeD*VFO,vw,L6?-%řغV&9H9D0Bt8S%̍5M$m8ej7#;AvҴcf?PhE)n.C/vRgTSI)|>۩o*0&wYt;YFR(1ʓ~/؉B>okS=eti:S4̺X>9kON1r ".iXF``Em<îo⛝ZD-9{ss>i3{B+tp4lW%[{44]yQ>$m'1BL1 sL :KZCC|9dkӀmeMQDn W#<#~9^sU__^C_Z37V{n\ȯ45h`tR뽏1;C+u1ĺc&)VxO\MsV3荔X@{a'NuCEMB )KD%yFఘ~+Hiv}޲AkJo82%N"mߠ:`AAo2 Ԍ]nST+&7d֥:M7aKwYG ktGؿ;qx~qq?s @^}}p] (v͠G3XNٶNykF=AIaQx*"XnFn`$'Y>y2>xɺZP{֊IiVO_YѮ@p']) rpjLD;YxXEKץ'ģoO_!?֙+'^c t2k(&AO(j;+$ǏG'~-p".'䖖J;,b yWpW܇㚴~k@D /΄7j=6%4#${b\f.DG_&1_d|:pGriily>,3;fH]Y"ÛW$(=[p[W T'lxH\[Xd<ɀپ(%/.٫G(1٢vy70G1Fz(GRr+Bɚf(X+b񓈮g#ּF9[ࣹIrJt,DxAum?#FV{,R 7 i2ăm 3djBvD}"q?ڽ~׋O=/aeB,1nR):g:p͘染h؃n@d )q#`ŗȟ+tV[^(^3˓jw`o>1ߧ%4P{@rN.N 8 *,]Ij8 x]1tL hC#?*yXlqp 0UP\k`d "om-oHnϧĕ=b nBG%G"sm!b6`iY hYqtR4 (d' tPHrGF(ۜUpBYIRX6BoZV? Hz#\J8DvhKɢ/f8߬M)66J[VaDy=iK>tEã5:{Q-עc,YE3vu%$k{t@o04HP)^>enMd/NrNB*4ʥ /:`XNޜM&2=4 lhhK.U!> }aO wH\Avpj엂 ӯ鉗TUy28 Q{w !q~p OŶ>&ƈ峯ma,T7(-X+%q zk\[s ƿ>!Kwt  n+$&qlZ> ! %ip]g[R&v$o-OuSې}8] IyjxQE˔I(2֭P`0]%Aqeh:T"3{/`'a b+@ɡ_ߠN>VYO#.[Īu=fGsMOiR>υ&qD3yXZX|fq7M-V R9T6EF}m~xP>܄!m!s`TLH qga))凓LVAIdYׂw~/BD4ex'+uyeTg v:*Nɧ-<ì{۝Cx_yQZzjEPdM_ôqrbl7:[BAxE*-+MJ=Xw2v(z7[7=?~F} TrVy=LWQ3RCaKAO+ԙ¯ ޯ76uXmCj}eOV'6sC\5x6@,}TJ2[9m(r&Py-ހe49SQSR&hSoafK^x=Ha uFO{y W5H#.`-P*lw@Ĭ7!᦭brɛ1LF#QYkY!֣^NAžk$3=(AKW5\1->u4`EHuf;03m# Ka=t%.,ipPbJiu!h 0픷Dԩ3Tg.9u4"[SH!q{LL폣Ǹ"ERTdCl A0Uܐhk(s;׆vrSu6[Nz9hyu7 T kZG +O~s8"OD'Frq ]WZ< ѓ\6]|Q>K6hϤo)d}. Zk~@QXӝ@IS܏6kfQ}' 38 ,ě+3Vd릜TCdi6! o4ݚgT.WYN2[pPGYȫpYʞ<0U5\dnG`Y>Cg ɽ""$@dS<\gb N2y2 LVn}Gw6I;rߠwj>W"Ƃ0!>PM!pn+L >`uQ<D BF k)F㬧 lPUQ<7Ll6=;AG'+F/k⤹[0M>F!qa 쿿8qr뤍(U ~`ټׯ0C1Xi`zz˧ NX# ;{8XfA055,\~Ri;3TnZ\KTVa2 h#L\((f@j"ZLY$ǚ_I2͝Zr~ReC&o0i7WS{> =oM*N \2cȹX4d_4(/L252e^VliRp+3goamD6(|?C\r]<i@,÷$2 ۓmkǫ.ϺJ;{>I;:5y^ٗ>r3| 3 swx1V11Tx^E!s9Pku'8K!ϧ) %Ƨz!<39 >G²F]B\ZH6j#zȱ>wEwD8`DJ|*jIRe!Z]Ĝ[]D`=GC$s#kIGVYMf #mqq]*9 4(mE%Y}Y<+I8ai6}QN@?:\a3R;mG3B>ߓecڄ#B#!9{%N?|܃"HQ) cIRzRan=s̟fyG"8zgF@ c~*>1Q@=t^wt$8ne ZRh;3j=6Y8~ 8䱼akmy~ҏ.9"uv > jX* T(k(=sT=:ѓي·f5qlR(Yo8 X]+L@Bщ}#>׉8'wU"U{0֜X\rhP%Iz/*8PC E7gAp2ߪĺ*yx*4Iz7 RRʠbȲU=B>h2tjqrbѓ$_x9Vx:^I0&Xrg C+P>XcuBNWl4i$u޸8\rw% kٙ5>P+f9GyᑊJ@׌M:s۷svLP:dF4}6TPxq"=ϕߎkڗQȼ^24~M_'L/?p>9Oxٺ`LPO|UANkv$17;%A&1V8Ǚ0!UQi. JRm%kkgV['N̑kR]xX*@3 K~q . 865q,Y-|V``bM.Ϳ7AFlkl{"행`X;tOaĆnˢ.ڐr,˶Ŗo,빁n8_ nk&e6fʁka1[2C0h1I@|a{q(6MM\=7$U2Ha8?N<;_=tRI=eG{Aj?¡m+T}/-:TM()--4-Uz κe R{'Qv %{JtA6ƓFnpRx$ꥢJMvFXSg~gsҬ:uxÙ&3'~;%IRiTe]B#SpPRiVPD.N(1W`1Ɛy4Q^~-bnt"z"dzS_&梨+uͷT c=s3a$wXg|>fBXr5Nc2ysT\ U8}EZ)u#B1 Û 3*@w yuWXLfTƨN\ h6 wsPkep-h B1rC q6mR|pVF3a[udڐ{lw/|Rw ؒ0-[= N;}\*@w2 SE2r"_C\,xv`/&`00"E2?U$-0ǵ0ᅆ5G%&p:_ea-4n9 7Lz0s-O$?VloNPqg]#Ch$L7l雑Ywo[#%X¾L+Teǭ_J};A"<0i͍8Ӌ*iVj0B6mzvD|-S%VCtܪS:+Bʑ#֓F{, 7ϿOP`;}"dZ˹,ZRsBc>C落wg?JCl]T 0sn 8,Wݍ "`}rtWWAT/4N]-NA-׸>_Bso? :9 C(\OXlL(KԬ,΢ ߠ YXs^ f_'R8QcyNk8xW` ynҋP<='N7p  sYszs̃M38 eQ@bp?5"xsԚ SkT d#Z;#g &NOƭ{ D(58ɿ[JMԵm)v}^W8dـ͏7t,ܔe_;3q,ש8#Ū{tB_L/vHQ>bsMWrAsh`{Ska kc/VLEjOڠ`Ki)gv?'qr-|+ʆjnZ o$`?E5{b lրޓF?7DL܂x^/Q*2v"; Y%53,>~؏Ayǩ'V 9Dcb.+4B,{ SAm|(!2r94ukI2Jrᯚz9""z-:'cQM mxUX-Wm7+Qny&{PfX&h84\{c~3_E1z?y=OX^Hbآېq8Tnh/ ~;X;7p$A[N V3B }%!U6K?pU}Vne[8v쫼lH|cb.M6`(Uc_O ;(CB| k.m}EC>^,-(s>?jĿmYm4*Ȁ6IO@͋k_q<ا"en1yW?Sd+7 mR]_rK/'C fr[6D+H{Čz ZZnz[0Ќ&ܐ\M]?ݦ tl O]rIY$"Vvc;:Rk? !D^GN ,Q#tVߚ.ø6_X?H P#ײ"}h%󚁚IJG<|`J\d$"hQ3իa]]8Y.Z GO]_\2=UyIUD3Vr,qF9Tvg^&tLTl W,m#V6F)[Cyi%)@.P"i 2g rJEYB\y_RDy&Ɍ&PX ׌meaDOEl3hDz $^~&E;i^SB{S&+s]nD@l@~ڎwK4&ā{􊰡EV2X>ˆejs1oa[fk4"w'ZJN>|PI|%2FÛ,$MZrGT/fFh*K0T)G] w|)7!񛋩;s@?ʷa"/*3ԭ͌&n$*[mN$C'ʎ (]?" MA;ˋZjQdj7a{"E83ψ`FKLGc~9ۣ{>fsϠtoZm'-һeqK&pmFj {-zS>؇BKuwuJӜwu C-E,Iz 'ZK:H5A]n,uDY 涷ld CTm zh9}͟۵fhpD;5R.taReU|څ|٫y-N!Ex]h^菊m+;@g_|R筰+g"<3^ɲ%Ie&c;( :[W*hu)R9*xGPFP"QeZK_|O9Arه- 3w pz L1vU%z1,gTWQ䴽C@zAԝmKln&Pٖ_@D jSEsCvڕ`j|51q'D8]JAə K;n*Ǔ|!};.4_L%XT1,(+Me4ps#Ը=pV5+yPmؚpt.Έ*宖Zʖ)-? 5%aq1TӚ$M,0RsCx,ϕPX,mLg*J HיLRԅ'FF f%㲧Uȱ1Z:n_ܢn]iGq;&L$`W%3"\F/7Kenj`OH"YՉFZ~هB_ш9q.L_ x1K,+zI&;aߘv6l XRƅy]XGmB+~1{b) 3=}Id'8] p2g^QZ.>IGo)`:S#͔~*&qP½wݪF<ׂ<-\U8NOfUDDcXL}ݝk.b0? $Q @֔ ްa/"` G6Qk 8m <ߎ@6aP $~ kg=9ꮓ> +y[}{%ʖY( gC%q1O/wv"- ~tDAo7Z\DxMċSITg::psÄ,dCB: \M%wVw!Bڻ.SaD-$RYTC-W|rTŠHH{T[I?ֳ`s"] >gw(*Z MJR?um(ݞWhiX-už%:A*0M'qx, &O1 Pqs#$KԴy0e&_:@=~iAި`T6/]lJgDO |fE u!cIھWE 흯%!ՈjQKиPSy*?|p}4*b;+2ceVx,1OW}9N[_7'a7_p*!CSV htvg.J| +'}wiNc!6rlhɄ>'+#ʒ"ODI"?? FC.h;-LT2,#-\Ix!mf㶞*Cz097}%7VS$@˴).ROBet#}/GMXkuPPщNOrwD[f|"'Ftг%P_ی+Og$9,IrtV;jk_zIxꗯ~k +LzË#"6ugeX_șEgѴ1n Bjeqq@1zNS9o<(P?\C[<K /6s ohk.7"]N$lH=Og&ZPSImTz34qyؚ^,ʀϾYBOȡZ2C6ňlkSU ɠȀxOwe4ᚺ]ZFm8>́<UJS'XQ`TFfɭn^g7dӋX&}bU^([,u]DZKEbmfZܗ6Ϸ |o8 ZIp' tк5 /C܆wb1Eĕvl#ZaL٩EsS˹aD~+O%Vsy+9(?q U<ܿXVBXAiᔯc*U߳jmNC^2v)-^dOR̥/-<ψyp{%@O&WB6<~P!*ElM[I$[qQN 'c%VuM'by.#)qٳ{:~ w\W1C to)t[25gbx$^{XV`ӎ+!yOBpGBp=.wd%Zū%@uZpJ!iaG{gHhW!QIh)679" n #ylOͪЋfV31Pxi LY,L~*ۊեLw-jr#J] >I.rJ&oXP?ŶN@K)yƠpB9?5Y`zh.~Ch:A6%{53'eo '(Z9$<7CtJ.9=ga:$6-Дz9J%c '^Sh(A0ʗI+ )(+0:{%P?a #4E,,܈~Z}6z3Ѷpߡ9 ?!qz+U)}BwV̸*&\%>n\gEk}'v[Sڈ=F#}Lxߤ: }}oS8}$WZ5/%̺Z-I7-Ԭ%4,Xr'L@Jgw?%/#+\*ψ: {K)m4ݧ{񝻀gKp,U ؊NWO.y[fόDNBQ|Igߠ A>KɎV%3wZ[dE*ͩsf.ҚӟtT[gpXP'&x>`zi{Aha@y墚+ [kZx̓P7.["eXjV^o>;ȴ؈,oW?+ %,LR&7mJSE#𿎰v-ԧ[;rDC8c[R)mGap o96\KDv¶mOu~(AlW0m .s,v^KI銼Kee1UkfSb!<>iy%&;۶T~ q>us%T6(ZBm@ \s _wv D2<I:*_DZl1vq20Tm31F+.a\8.lm\eAqzD]R6LJw!vйe=FQrTvyLc5q>b0Ṭ#"U'pZ'YژX37-Q$f-1 hj.1hϼWVh$jWAa,8j ol^RCzRpb{@FU=~rm)3uT6k~|_7z [*$)M3!B.ɼGK ^@߅LEրҽ LfS=! /ma0Y5 j{bDW /obsx'%c_TXXMZ#lyf=3z`] \TDDX$&Niixgk&΄۵QF|5:* DHY HyR:?Sx0>K?FUT;AU,f(qeӗ&+5om 0Zk5#+6s]\wƍO1u=k-!L <ڤ/|0#:ւGy*NQ !]B5i*Lq72Akp(X>@Ȗ rYYc+i}lt ⽀WҸqql8U#A7F{[;T˾6JqTxM(iίO/. 9 OIREu|D͢9R<@;zG}MJt"ʴPx*maOoa@M╬H䘔Sǂa)NHqmbe5(u9{3Bszwܶ]nt/HɥH5tͨs4RgLl3z4T74MYZ=Q{#i>N #yB(ĢSj7)YTWӛ? !d p,@[:.Wy" `N}:+7gZU4ثuH ;\FgGΟջL=֚/4JmQh3MY;SI\zPP2 <.jЀc=@v?wa<%:>"aSMUG  {!c\&`Q%wʓ}bCt_TT4pXo=:9f&r>^ץrpɭRၾԩp\eR=LQG\\cKc=s[t:A2 "/ _*qEkPm+zCoċOWruw# jt|CC[jwӕ_O;baEqMݺ/`gB~4jYW92djO_8b!h9Q_AxG~ZN =/8:ݸ@2!J"Ec Fj_?'`% A9EE]Rn& e$)`/ f5hf^m%qӉ1>!νc/7OŲ n #xM'g*#ynm>`{^H iO$H ;Cs2Nq3+C:~ץ-ls}ـj aO̩K!6q>NXh3)90M6H/9l^b׸%VĬ K5nƮ o+PD6S1Sg+8{_1!Yo1=<}}-7kfQBX^P*c#pܤFr g~@sP;+ r3ɆJo f@\׽/?E3W|֫rtjk80۶^RrJtRDc܄5|wbo(x9;L_o)/\QA:=ASDL/x2 ?FCa.]0D[uRmx`Am H΅&ԟRnIowƀk@0M%aw^ `i:Σ&NBl<ع&欏;w_O@#ZA88X@,mK2N"DGKT)fʏL fS#><߷ 'ϼ+>DQXĵ&E +1 #{sWJU8SNAt 24/b7di݁hE0+Py~k'%l;wˡKB(M"4g GWez*ڒ4T+k'#8$;GO ӱ`=bdRrzHv&xJ\iΟnD7G,$o 3Y`L;(Yݰ?OMG`\M5N d w>Zĉ,aFQq#@ѵd߰@~o.]ʔfJPׯa(G3x#UĹ n ӡXT8Y6oua hMɉV#"yn/k[#pȎk:0Mqױ2wE6-Է ˞8x: -݌XZG8twz:~Si__b GirM_*pE=ïגp!ϐ׿*L8 P U2jk]",'|&G"T`D2K&}M?F(S {1cSd}ݻ(1j f]7V3D+|k*",[zAGAO T]5ד2vf+:dPs:OډR3KM:";f&,4~ s3MQxE87> >o,m4p.~[ JG&Ml`7_ [dq)"!o赩mqIC2 m.G\ɪlʛ3(r#j?zl k ȹjg/'hPw=P wOe/\ʣ=  ~$!"PIzp[A=u- Y<_+.f:ciʎ;1KfT1mulQeBbvqB FK[ZVS|ytM7VaLc⻉cЊ]FY'iZ<fy=;. M gduϩ9: D.9rM_܄% /I*db|8ݕQ2p($ĸܞwYsӶ,ܳ_9O9hDB&CoQ{,hC.JI'IbkޕziXh5YJ< G ~Եb(Z,M*P 3ErNW.Ex(_M buq胆˱"q)'h+l~qdɛi8* C-!0=bbtUȧmk,`yi :x> VߝJ `T(<]Çǂ6dhfX;C`P$ >@lܙ׬fb[/v8@=J^hP'<Zz[#h~ա*L)"PەtTCd~>`Dƭ+AtP2^"` 5[@B3H[-|LFg{u=WuV`SLYƬKIP Xa$p\muLPKڦT\{$sL`uӄ3wc4*ir8v*iFͫ ekŽ=B&G'M=vGZfMkgAhCX}q1yk{M/6k G6gTE`\#ȶLfoXϧ}E9Mg=jںzTf:Hls+[ HA ܻZ/jO 9P-Vx5?QHm&.zYq2.GSE".ez+R'y\@BG,e$) ml ᷀D\g , >0_$!vD*;ǭEG 1Cbw0Q A9R؀ȯ{nHB~٣c6>fFՋs$j5sc>s^L-| prEA9fb#OF ZRzK{ \ ~s;K>]p1xoC}b ϋ]}-?(MvP<65d)Y) -iF?\Ӊ"jr\jR/AV:}ecޯ>*ԹY߁w,$D 7Mޥ,Ì\Oy5vzދPV*qd|s"b%uޕWx`f"p,\4Zlr3ro+p^_Xnŕw1L`XL%}v.C ~ e/aiuJ\QaNp -#ZOXO?*2fEgRCa2-nrՐU vt6[†.T;=N[7c[D$~@x$ Hވ {O2wʺ),c|%ZF/RmjiwPc\Đ2"мqvS-sT߱aȧ. ; =3O%N0 ޚSkh$\ᠠnsX$6^f.i]C-WQZLifSԺ(kB-[#iAy\%G96E^wȧVR[P 9wasr."G i/vw1+$Jy3 L(m 3&cM Vg2qӀ;?(+|$BسSNL_Wt$Cv|4E%.> C[`m+&. L/Sa֪:}p#2>%ҸTE.&6({2C޴Љ6K\ʗ:9Hvr `_c?P4Nk< H/k'W9#Bl<yѕ"HԽ}\""mCEU!%c=)w%KhIŶBTQg7#ͳ!њjbyֆ48X{ެG7#Uј2xn vTf7 3(pm븝OiaVݗFOHz᧵ 4vApbTWF:7ٽ:Jfg&*di"k f-O׭ 굌=#iqY8}Z*}[Md]*ڐ{M,s1 cY˞Tw-]krΝI*B]cmi]gTd |f-toqo"7\LgG "DjdV96V f:TTZDYȑ #U^# F :0X>yG=vB=.!0g ˙א8e B LTPqV8 Q,(j|!QXv~)> Ҏ-B7=lZж`4b)Ei@WHGߥ*ČB.{=ϒxnCgTh6icssp{S;00m)Nxuw4.F:jߢ;jk7Ia"1;{s-Ձ!Q~;S^Sㄱ4\,_Ewcj1#l}}ͅY|s5vgT~x;gR]B V_%E;_…V;PN3KSUj@tvm/Yda(>7Ż`2%uX:XԂ_-Cw Io=+RǮ*Gw Slo0Y!9Zt".#JH,C*of@N6 ǵqPE#k& >,NH츇XC 2#4Ǖ_slګ8m'OʘXY;ۊk4tɚz-usˢ^@K,>p*}l^)9~( {-Q%R.QjK\v/݁WB 29)r1~܀8%TV2RX>YGCx (:2.gr&&S\zѰN[zP$HvQ(+y=E6  UXcPn$f(;nY%Y 9[R_jY֣kYVl xSA:wdZd PB&6Ab\9:Ly"c޿~h↬ ]bJt.l0̙\p#S)yg#u{gd|ZrݿP( ۰i?8x[t4]H:1ǕnRb'R%:&+UkQ&[STכpNCz/Z9M{P]k=b 6Z)yn}N|fm 6+35?<86wDҒLcy|U-_^%h;Y\ A`<[a!c(.b<M_v+ña/DKу6hu֠0S"##N-wV*K&ʼn._Z;)=Nx-Ǫ@Awm^Ka Kq}*{8p)R[_ZAtNupPs *1ϊY s‡1b,aP/gN~^^~;a|Sk*5HbFJfۻo.ŝ3")Jh#'$}) )G0!xSOf̾AΉ A^ee'f?VLiLyM[;t! }YMgY'xq;jޏ3z0zdrIkWUuWI5MP> B$?1B\g'6@hLW_=Y|=::3*#uB@e')Q=͝=rCvLy2^j*Ka;3DtSەafc} /odx3h䑖v`R LQܹۧ5  ŔD}KY b=ʵA| gnL#~8uU|7Bx!S ATE %Wϒy R)ufpzO*YiΏ@a܈2C&E g[ܘkTGͻ}? uFx&]2H vO@  Qb6 jUL>k־G_vL:d _Ʊi¸ȍ;?:y H$}~OT:SOjZ{X&{yyZ=2VhUk.@wnO 3;c%- -[ӝme CFul˚RZO [Ln|23[~O&AgC,y:Va9eyvƇ7<* 2jF^7,VsO)Iڛ`kM.Dh}W_s-SlDj?P&^Y@ϵ%1wUvq E% q2@Y58!1Q.PFI3ܖ2!; $w 2ՙ;C{Upx]OǗfKUIl`jbx#IkCT>M|[CIߝٌ*)"/+wJYS^bpz?B}18`sK s*_-75=\xZF:Z!О;|h߻ejBb2\g#LX]Q2@\2)(]ft#8709|AKX"JDkM^6ZcaO :鐩j .(K 1)a&`x/@5^#*.F @eq8FR;8؄h\ OK\甦DEY&KCBLiÈ=%<ƭ["KG.WFn@Ry9qdMd~аk  W0p)+ hAXnAk%'-OO䩀ܑмFJ"Y*$$񎜜1}/3E'oTFCs `xV5<V}{(^t{ZOISĒ{ӯ!+h LlFM󚾔jXDΣg,)UeAZgɮ#XiȿUS1y*QJI`%? D=Js-Bw=8ՅZ.-yJY+ qv`oZ-Rtñf!a9Ҟ_c@i1O)Nt6=sɛdV Zo{F/E@`qQYe.|ev%|𕪑Q`OA-G_*,߼$i pHfv,fЇnQ`Vf8+GZc;jHQtj "C246m!{$JrzNi{[툈MFON5[ۜ! JMsG4SYPytD08G愘˕cwԥ72xAZ3Qwz疳И+`TwsQVHcGt>˺| eH)epi.!3-ǹVL!lF8rwtb.S |mŊI_wMP0x*yZ g(Kӿ; )l,…7GcI˶l[b"s=I@.v4<]r_{zF&wc}d" -!w5(fS" TMxG?ͳ#ͷtP6DK\/ i|6*Cޒ1Χ`^TSN4ŊhzkjHrCa0idp9P"=: g%Sj6w_ dJӛQQ ꙃgpT@H0UۂjP C}0KdB/|M2LHJq)gJW.0\`8}z B9ʗyMTw5Hn^`}FNRmڱMPݵxwj\x[iԨ7TS lw&F&nQnDf9IRU?ͩbRLvy? v]ɍ_8JϜRwrc5L˪uqu;9Cp&#]8IrHH(l?^ I&F_NGYMg|gmwBf=n?斄~!H%|^nћ? H}2*/>4H@'5!(Ok@E셒6F%I!R#钮T6oP<޽/%JAtAa$A<&QHf}XRG OKXH&v Ee=hF;ŷ6{31X@ʇ[Zz3܊ލT,at Fv_Y^T<ُs[D ky, pDujų% {71? Cwx[xy* cb<(Lk\NbhwO0HQBPj'%b%zfcs'Fre $ԌZi"hW LߦqҘZ[/}['45O6ͱzG1=x6>Y3G6wm J" W 7풽7dL!.3D}nC<ʷ6Fv a *.?'ǩ:|FDڦ0im X>٘s-JM'˚>;_8 +0n,w!Ŀ{xr=a,1R@M1>lG)>ENHy>(Bf?!` sJRKQb ynPsRά$ef~}ݲ~1ٍg4 n[y^{P/D'Ԫ̴ 塲%TC"EmM/V qɓ@dWI3HfZ3B7z2YJA92k_Q},T[u5)R`"_nPPy).& U1)YM(uL;3~Rj#P}b2X*hB`8J՛:~>qb߲ޥ7j츂a𢡊z+s- ƊRI:#)]TrL81ygVl֌ZA Vo2ZkNHvJo_YD> >k݌m;V}|T?M&!yb9Rhxc=S2KHvIhႦ2Ŝ'T.MˁϒizɧY=޽`*SQBԖ:?yKgVME/ +|3CK|4&W'BH-@r@C`|?E}ܱ_i8 #]ЙNr Fq_ƂN :4dc {]O=+ۧSxDw4x0x2j-*]D"y>y0\G5snKa@cNvט.hV0k3Ca[G+P>jq?[mv;W"(|z̹ȭdFL@,X KdX*/_ BOg4P>K֔W0{ T\ %%Op`Y t;1'#){SG1w2C[teQִ.;*e#X2|䦍RLଉ_f2 ,)'ת'&:7R!Pቊ W͵}.zڙqtSW/dJo# /{Khݰd/(Sx`c(CD|0hoؚS0azp4j*1 \ꚾ~)f d>Ԉ:l 73k ?T3\k@.f[9Ǖ\WrNW;z{r*QJ 5h6pO!G]a%0%bF^ӫtHei^:TR5;l9SyCs*m1@78r硣w 4d1w E,k?6#3/;H`zWC:7tinzt0Nۿu[Mϥ> \f'㻳byȽ[Jؼ#r^ XړX/w=/k)-μ~0Jv#ɴc Olc?|s*JQO40(Pup[8/A??̣Ycvx'*Jim>w+[( oV=I) (ėX *2B}/Idk<࠮eFǴPVE$k w%"XvNSh꣔kjlB=hθBu(Յ*=`z\@$c`k)L)]D#@iTMPL~1tBm C*"`%;֥6^Nnʪb-b l~!V0^vҥ Ȩ[^aB ajTw&c:\!t,AA%dqN 2R'm;j 3Cq=ﬠn89[mKar?0&7x̵1j%bm&3 YCK=ϭթ`1ywoθWXFe-|sz׿{m <-jSc.]B&D1o>}X>E!Lwn8evd-5Ox2DhFWc0 _>gmE*s{N73A= s`n7R/;Z hff'~`~Id„ԱQ?]G1S)lwړT  ͅ>( iB಺~ZFM6!6UNet}q9s꜈S7wM @ne{" !5.WƵfgnm*גN7-]XMօUh&ӌnϜ6V\ GVe <QUp*=wVAAi-xYA .Fh$31."}l잖;bgC֍zcIp\&UӐ`eDJ ׷UySyJd-:!e^x8E,Ļ )i c|6J:;ԋ4d"'9`#}&hh y FBLLyԇJSN#kX9g~ؽ>++ň}|mFΓ'jům4%0ViF\*l“$ #PV)W]?VkI ^cGpCY LJ^V+ z2F)U[9L޵D߂äFJލg,E =W*3 Y^*M Sպq)CZiNv9{}Xh0:[1;4/+ TO{Y}o&MzPz- 4./\5'CKS/%Swl7i{Nb6 .ٲw57MB5vUMٍ͎8Cʛkw/GA-q Ü ^!طG䆽О!F zF ZĢêDZw='`"['`o&ͷ}\Rd'PFrsHV[|F ;pn@)ja@Ó,pМG$خp_h[}<+WL:QQ?iQ`sgc~,.Xa96ۻJ%ڶ|/ ƵEz֚Y+߄ĪF< Pθ|=IJBj' X~ϑfmRЇȼ`|'[ab5#DTx bɑva;(:+r(orZTr947Bfc&"5갷RIu%jf |b{2Q"sjoYu?MF\n> 'p&^ofeo-Ce%Wd#*]; Og])8Tz%cbfBD/w 2;1mDf~XjEE!꽟@B1P<vY rn"kq%{aS,#E%Ll-:/]8U+~=P6Q <ǧƣq* CYY1>!}&$[RϏ:?ךL#a-Bop= TAvo 3I(pzm>-/4Dl4.+) l&ȇ^sYئJKwfTgMއKhocmeEȋd!at %K1n"bqr@Ŕ8tm\eU0#=?:8Ё;q_,X"g_Sn;vrƌ XZae@}#Х@YL֩6H@^> ҍw^Naecm!J6qQ2M~_8!?4kk*˫/]: FƉZG4@ i2B{E\+}ш.pьe@Z3-F͓ =4>^;FTNoþ{EEX]te`ZW鲤T | ^aD`oO+?<Z)h)di&XN¡i";uzczۣ^Xa-~W+T3%A^#|!7< w<f9LnO`5` U%X<̾@xٶq[< & NPˉ"'G NV\Z 4tx 4sK7_ {^͚EKZ G3o׀lIB[}2H TO-0(`S/&42hpHla(+cpxCKGs7ixH̨ {.Y:{:Xd"iRǑWC+}M˗s%):r[eTvM8sb~Ӕ I) 97,Y"^FpOPlQZ=T`8Wc#|QTi HxWOÃ_L!T? SYMP0=m59Ɠˋo ek#ϕ8_sz:We\O{7mNÉ*ݛ-SŅ&3IJjTC[Padi@a$[8d9y2Rމl_J5Aփ1ײK|DAdKg9~q_` MNמjr!=s_>6Rܤh !cpyhZ5#WMTTuYfFX?71H-YOg ԍ>Dב6B<\~@JgXG>ljuQly?Y#UɉEqe}RZYҒ:El{ ,@a4ܞDhپ7pyRڻ;ܓ; yٵ:f>]sk]H1?g`xKbi^_gƫo| |n,](Ѻ[E"f%tqsbzr*'1l)Q`lTc\ RR?Ӣ9^v>z}t v#-R>#a#`jv?'9lqC:ӾA|)`YD4ȕv {S{lw8;T Ow ׉LbDX] R5^dtL~ Ccea–A Tۘa,+)i0HwMJ\ fh2} 3b2t^B='') -TbY 5G^&k"57e,?4M1,Ѱ V쫻LQg_9c^/'!2Jv=)W'VvCxW\*i"~$lZdw΂*,Yrr|^mb*k:̱ie|TV"X"!K77ACl TItSdRjbИU=FGC-6guɣ2R"`?_(HLx@}'g&<ѝ;S.{vjt@K }+Die)}+v@ľLCM3Q (M Z aI-"[!A:y FNR,!U#Tߵ$Hr?َƢ1' Vz 4tKCF.>ԍ4ִtqąĒ~!Ł޴i& @ˈrjS>C#vP^뽸kKbLT~`+ji g'X/÷$iq[-WxSEqad3 ҈V/ui_|xS_ו@lӬ-oyY!5/1~x ~DTҷ#NO 3@Z:qWa.&g8&]/k)#^LZ(8s/?Cir H8$T?3:Bŷ9|^XĂHDŽ=Yw(r[}!ƒGPr)4>\ϓ41Y*Trl[)9ZcGqUF[uCfK$BYo `C96iHNE)j5IQ.{ۆPO!;.P/ 'Xz -ypd `UP?ovTtƥ 43%Q~%&X8e4pnxIzߨ1oe撹Η\,GC|z zJ < sfϖq@C2?S5pk_*<8Z* K92r' EI{6_1iO\eRu$с#&tp}i v IL2ЬqB۹3.P^;`"ݿ6|p`PP{HvBn2eB=(;O@M/ 鐽.Bv)(,YS28xYM(H#CDAdi9k!z^sZ7? a/z]@V,k=* |+ѩM.(3C›WTp7ZDmsf:KzZ#ˎn$BOc@zLCWF+|o˨ށDF"c<͸VgiZMgCه xX!|}!3D.Y d{C>F^LYtfk& x;̙@} XoeWM7B R*F}B&w LVzۂ)3_"`a.4*W.O11z` 9h)jue҈r qS/೦KVhDq)*Bdr(BLeѱ+)=($,'BD&7K2HIǴ(V7{=^#"a\ ՠvzZn\=]9&=+65*|hk&S'6&\˱ .Y|x?&%)2p "=eDUHNh!yy\ú:E^aT=wp[$ź B4ysf.(>mz 04cLV6d^ }ʯ2cX9.] MqP JSqP#]M P30_}m1M=^ʎ|t]5wKt_\'l$7%+_ɸ`z"y wNwq $ 6-2K /XOTG-<ш }lncWt3HP54$\>fe9 Wk$ (ޙ(' sǃ㬐[j $]I-k;YQ '! F'. z%̠mj 7J|]vOӷ.&]U:Yo"<Im"#/8q(W9#sElRO|sRQ9項cC~Pr4FoN<[Ptb?9C]#֑TGUes,XsBψ]e2=xN5썘ձ0߸lst!DqAE͉+"DKN\"P*;`Lh舍_h}UDUcC缊g=csڰw>\< T-#9"Yg)vݓ5^R2[3nIB{e!>@=&3Y0R)e r('cDZ[S|\8> B #^Y|3?y~eB&C6-QN,Y-qxG{Uw)UUGc bN\H#Es1q¾x Y6ĉaKr^9dH~S3ښf;*Tpy%$<{1L$HYp=ޕ㡶zSvYuO,+ dzͬ|*(F2"td"i #k~ɋzS2s97*C]ZHr]|,vJC#9(ǑѰqG4m8TC,?Ycn&B"Oy$CcS [5p\#X;pz}"߮0 7?mIzpCJ#)?:{h3Nds# Aw̅n/&!ă5`L;ļ$ʓ({k0˃jN^vNWfC4d=`+ I|qsIj~ũP@װ,` έD=ÉN{ju|%5ZiCj)X cf4q?R."St?xdϷ=p(\3o.i=tgĩTbF]4'H&e%B_ޤTfp-\h[#(IukF)@.tRxh"D9Np NOOA IN (!;K6Nv1J6-{8iZpY#Mo𕐳ˢT,F*<&pժ3*@; x6y&^92qngr1KKnR $dc{@Eؕl1@Xl=^`,kaxS ۂ +p1Y +W词/zBqe85T_ BPODr`?^55Z^Q5sʽTQf?ັz>2&Ḓd#^lB4i_6a2* ?.J:225r?Dʨ(R~컵ڋKЉo7r/{^;4= iE[{~do]*5GV ^%ыZG*LMԵ yODK\ɋH`9R"G uu+3k8KS=e7k~7v\ fMRH^67~nXRuŀ^ [ rX72E2mֱb(ME>10;=ZUcco7,' Tx01(aq< \4 >9ۅ pEH܆ƍ" P[,-%kl"ڹmsthwʺP"}< {Wp_hпi0,PXO*4Z]!@pr+OpT\Y^Hly @֨0[ Qi0adgۆEI"X¤|TXJJW5.k+yZ7]-v5_~785!Qu[+cMƝ V~zg~6M 'ujK5L6xAcw-):_9,M$8N.|t0Fi)$24 MT-/q4Rz?5SPGڗ\++2 ~K"媢=Lotлl^j2X̰XD zK¤? )ҥWiHYM3Dj3GT:|YGdWdqv~Ȃ9Y1<"\vAve%ZJv[9/LSf ߾nҒ{8$',@d*AB!0HЌUQMΏZ!# 6-0DT6 #şg覗vK6_+q:vɦ֗1XY5`pH\# K)w(n0M-/@ZazJeљT@m+BҩQA/1X>L/P#5GxGmJQ'{7'J5 ]\ NʊS~9-_s z XgݟP%^čvq]ZQl8+wJb (Fe;)_V5;WQ.Yv n[ޑ L\2K2^9h-y(WV>~?0t(dJ"`{YOI(M_NtVRJD:;73݅oQ0ji,x ?sށO_.~."mF _gqg)⻬ȿیRWc4ϫ d "Wڲz.ӛ`j~MVc'DI)4`5Bu00y_8cGQhP.6lwt'&~zE+ P'o>.R{1oᒺ=|iȢqMh⼓6k8a 8sJ.'Z:|42tw`=D,Eh2(W4 k!e'qp(Q%O.l9y6Efw\AR>j#a$#Fh^ /sګ5$dH]U\buM4?:ʈMPe;O=lĮ|كϊM$)k}/NGܧ\ ƗMaL o|z^I<`#pbO?`7 SzYqQpקo-vt͠q$7gʢE[RV~^Y'5xlU7Ǫ7¤/gf\ypEkfEZ5[tEaCP|r ΑKziM*I5Cdvm:^6l2FG~MQGW[ۆlS?slaw+ ͠f‘vzFg L6B: ڮ 9hMpx_4$! t?XypLKaC=,z^n| lODvtKNYq{$RJJޭ;(t:K[SU}J*/>V.QL˫3-鐂lNiK 1X\j\j#ΰVqyF8 ;%ɩ@W6)U4-P;ͮ.k@Gd_tuKSe~xfʒz@Q\2V_@ShOh 3ßa*zI,d>=BX5 t}Xј 2uQKܹ|dT5R&<,aȮM_.E~h oSdF4ɛYj? }Ц5?Zb 0.$@a~BM;vsrFȲϜ \+GVe IF]'2 V4kʴŠ$bѩ-Mn+MaB8PlUx@^vmAg L "Yl\l:tE~JHNe8MڼMvoj|:!|,>pVKG Ȣ֡GCF._-ܗIb I˥}PD5ٗ\èFU ڊ ٚT )~SS0p}BL@0`% -!S1kN ݩxe4&\ Y"h^ζ\4+a |y1|U(M>=KO-s_̯~~AIJx ̯7pt=?ށM©Ry:{1<{h$Dr[![!$@KـG8&t~1"9/-Y3TpMG'G~{DԽp`"LGE{1Y@83$w`H%\&e|z2T(N3@M3p`*5;D%:p_-`8\&IBR?w vcBcЬ_ yʾ1Wyx)+ {d-IA E$.ZsЎy$bc9BT{FSH~hH%0hhcaFq a_ٻ>.&MXH;)0fzROZWu z߽://r;N]ZРnȋ|IVr+$9:Ŏq+|,s4W{Jo 4 @w"0F-MXbv}KbwעϑC%+']&#EHpJT-X/SD1ϻ&-C+NBd׮*ϖ{644a]DKEu=AᶞnprQ@sJGFn#=>xNZ3Qd=4)ߏ36h1n&vxoOȝ{?,hr KRda5%Ljӹ 5]1"H=y}Ud'y&5ǝ;ڽABeJYxT`h6PǞM쒂 ޴'R0HH8~}+(M%I3,ǏHgpbsVQˬ>Sfk{P=#W%Nxh*Ť\[ 9VL W/1ve3FYpYTۤS>UV\.j\l紉vu*/oixxyb"0!aǍW˹]f0v=N.Nh>7@\iyt8EQ9zL ~R"?8Khi%p=v0|dGWe;:iyKG9eZFYX>5r!dD9G'nBb)DђS,C4$oƹːyCM07"lPd<{rVW4!aMR& gp$;cf#x& sҞcGRjC?42)KqIf eIKZo-9bR+GtkB0ި'D,fdgUIH޹؇84{Oߤ%;ԋ"̈8/l r8iFgs HMBWjۢ;D&3(QO4o oW$H+mZ8] KTW_f:/>Z^GÁSEXr zx<)WrWG6>˙_E̍RKi"`Tw} ּXm-+Lhރ4x[2'Bb[9=+r6=YsG)IWlr>| P[ $ċ /~춤a uu~sQ P!|Ǐ02ky toHP7b WY MeMRk)RA%i";2Eh5d }Ba$0$#p'يYWon!KVh%NgL,%0җN] h,"wdd|Qu 67ɰ~wC D[zWb&q'pP9,7j=QƤO<ݸ_3B.+эqT 5g(D2t4+nhқ'l4w *|O~S@j9fi.ʲu:0LHPH È+ eɟæm|:MwPѬ% 90&!M!k I'oZ^Ǟشx2'W 2 k|^; dmPzb#JoC\V(h"\#?%ɘ A:wl{ssW5-B1pp̓ &uT2xk25 U?o*m31DHtQyra\ E#]5͌}.Kw]ֹ2 D['za^#"G)BK,6mtߜͦq?oUC+nlPT?5ќk8d ;:\JMz 2s%Y >b䬼pQd>VQke)9;k_]z!ؠt`eãLD<f`G#f8ICKVzL!?wQl&fy(JD%7ۇI C!ͤ1,C/^92"8iY{|꼾ǧV~l/ K|A uKkN0|"Zʁ*an¢#OiL†R<JȀ~`Z-R?~6pfvi,[+Fo 6§s?ZCb1 Li*e@27hi5cg l7?=])#A-)g]tq/bbbQx黟ɳ5]^di0S%|mw R .*"xdNΞFN7YpL8i4>xM .sM1^YG/z[$IR`=iPrgpbl<<"2<_'xp,2i<2bON[TX-NH>u+[e4@/9j+\'-A9IÙ]d~ ,KuPXyE]/h aFҔ}m8}5Üi2(T|(. opNP+3u1aX-t S' pcwJMASXB\wcIk^A40 @c"T2(L =ܚ}-tWrt=.za6}fFεq;wj5ں^oFVI~-[@~ @?hRg3R=ǓJΑ阡9\fXvi'f6xދ ݤ/xJm2c H]F!J-mgsɗch%\u Hi%RŴxԆo/xy?Rz'Dܡ`%}^ɪ6jCE*aDE,r^>`;_ݟjʀQ=| MHgdaHCH.DWlֵ Ea6(D{FZ7^saˑy% 2牐t=wɴ}  [_9s'fźπx~?-D)3o%eN\"Α2 :)Y'Gϲa/hڑH>&֊]aքk*8zߢk".E[lް;.jn{vWi.kք-c?N1 %x1Brֽ VVn 7gQNE04@)F,W~ :Kzm|gD6^@+e|9qeD&dDl\&8i&`o0s\Syn69"ejfu&B wo>ږr7WݜǴQ,Hߙ^캁:KK@?@Ǵfzϒ$tc_s )w7bܗwu`ev 9e FC2\%K(q,cokF$C|kљrN QêaN嵍% mxQ~&갴DnV^^QQR93s(EĵEi}OzEwJ +ɲ".kJ)F\`@yuV 5~/[M-PA-?eOt"INѶF^'gZ7LrYW;'%o^h08,ec i Qm~!"LhfLE[]]).މ\zZAq)fߞ\Yy)1/LaA1e֗l߮Nc\pם:PP\0|5 <U}_i#H; G]K2N?%?Y5<:MW(m$+pVa;CUqqqv+S _I!Pr'w չUD1nRkdY+ 5[%K?&~Z 6wl8-_^COLY¼27{],}GYHsNryioncLۣIuqRt38Sn8Y8M_ux3 VN9<[]^yKqb2zIS 0ir㛯2=BO!3>#^b8V B":*$_[`+ԦC}Ռ^|1! MC6X fH/9O.&1YyA8 ,'l}p-Vlt0{8_ߗ <܎V> H8"bN}$wI^~0:DȃS.&Uk&fE WPuϤ>=-4IjɄxwӉU0Ax=4Vzͱ=id/t5*A~ƭ1M-zaT ?)'"ZV^>6*= cB11O#$vwn$V悢.w9绍/HRW(sazԍ5(U) Rˮ6􋄈jxى Iᏼд$`7 mW+DݧUgKTul(dzqzgh4KpS(d=J‹gᅓ7:j?k;U"efCl!=gA4 MF:9, n1p_ !<jdwDm͸p35=B3#ݟ/=.L fjF͸V3 WT՛~/uI;4r|Xd V!ؿb Q*$Ar6;^B"9j{/;CeN|2M`*gQ&rnrY!sr1VBl2Rc#AB#|zhnxn'/t܌ xv\pbև-y=Ѳw> 6̔ D+ 3o-Ou{DH)򖤥4Q045SlC FɛIJ-73@}|XuԻٯQ= 2 bAvMI(vxsrdj#AYBh5;'4mZWBhVJ~+`&b@C&nĒp܄Ei ÄK eMe68 B uuui@xh` =K _b' }0dWǶ&0:kj`f,Z@e8>ĥ,6 J# eG/٭жxOp!3Jy1O9WH"gfY+珟6 e~ ;e`LUX+f|nڐ3ذoY~T8'm6o{ xħ𯎼?sOG5|Tc`Gqy.-e.ba@ zхΰ@1E#[7%9&| eLpZ F“gI4GM,1G9 :pD!-f9 6YDe0jmSKP2Cf#WqρMsUg{e GE @Dm4I"i93˨RVq]U9bbulY߾U5XU7b^'{P/Pos1X9#2ӟ)"]&*6b+XPt@Cm>4*O húoaTV*)_ 0!X,L=e"A\ U AdE&e!"@!^+G]udj23L/u 3P3{o*_G2Xw,,QT٥o}_>9FF/1`: !>on뒳&_wd"K9GHTɵ-<7߬ܛTl_ݵP$_SZj:ׇ1>!k XWo7 z*R&D-sVDn1|n__B==x $s}5[c{r"Ɯuk>-M3vڵ@, 'VeuZhFE YWgFp)>(B}b@ڷ-%yom"zd}vqs>E-9h@2}np(ռuRe1O>"j/q8Ǭg!V`lrSlUUFW~vnZ.Hkr9cu\EETE6 h.ς> Q.x̞N]X|xŗץ@nB u[ &U[RZp9t=_m23k&Ӹ|;ʥ%!O=QcO.mБVU#0$?;@f뵔]n.?AF/qW"O~-@v^ޕg q~2 %=pX:`߮eQw5IUf=ŅJMJ!Luzt߱`ݓ4,T:jGA;J*M FF/u2lC ܾv&0[u)z|w >~1;7bm|{d7]ʁvoaSnic0$Ҹwu5VwkXQ?1=Pْ@i.q'5uЈm:! i]2:0j#8n%f+q7'{27ӟVz-5ε+~G؏BZxNL p@$9/]a{ :@0)Vs߲w>@.p꠶mLtz8@Zeñ<&񖛚9e )zX(L MogNi*[7mK](!D*spDLMVm \#aɧV}GqEoFJs꥗ԌKHGN|-Ջ*Q@SD f/n}5a7m5} D }1ѐneq$'d{45:O:~vMf`Kw AFD \uP/Z :}~"O_q/-/_&L_-SNkЬSKPa.(tW5H=ԏJL-fHpcFufy 08 - QO6sJd~wr<+mv:qd#)qy1`bߣTܫ\vmPbP ه{s(blh% ,4=j1gm̼f?I$:>ufDo~:Sr@/Twf|߶8L!+&ӥ/F}G0LgsחF—l|35ʺp#S.B^W-5;7OοN(,NR6+y ES۝uzQr{BZ A.m10sm(l6-Rznaj.d7ThmJȚ 2OڷfѴmXVDs~>GAC)%3~A]bطxeVۋÅ}uSVw2#u;Rh#88m**U╶G": `Iq]#xՉaOp&o j]alwXэOvW~jjv9z&iW؛*]m5D"pk@+_B9Al08O`:k޽EyjaM3cHruB%Xk, q8 <`>K"QZ0eɳ!/1O*UiP>"B[E%K2/UX< nrH˳[1L[J-˩97V9k=#T(ŷgz?̪$cS_g1Hv^E -so8rف~P  dX|ЌLL#|u>GIed?Jx+[2M4]$ib# %!Se燈-^qXU2de#R&rI$EChh 3ıNAM>q"K#2 x0tNUӉM]Cp%<8n:]yIarՎ-.SPd/ӑMf CO[=66׃$l O), fC4k5<2p!GNROȑ QKt f<)I?m D;4F l:~ 2bIW@bV|&/!g:0ڶc,O' /~Sk461&[v( "`}7̳P63t?Q^xqim =4!J_AMNz 9g`vNgUaSu3_Z=[eY$Cp\Fq!ƭg9$fD>^j-t̎i/6005,rot!>-'OO ~,;Gڅ`; & ܚNMgڹF4. {.CLo6jC ]iI5M[TM|-(hHW%ZS6q}삄E=Cgoň"}Bo@ f3M+,UznkNJ_>sYhA,"[pfNGՔRee`k(CitPjOR9q7*C$>k˕㤶-dӷN+weXyO3L u@I)y}©qs9Q*Dr< Im@Au<]QO!ui#I}}{-H/,JE&l;tq&7}s.ؤW"9-p?oGY]TZuh!D%t_ ێ,W 1 }HldbSǝZ[XT -[_QO:H.us-!l?=iOMAk%K7 ?uSю6N@0Ӏ!OcPӓZ(j:IcU^qۏ,(9/>. mp@F/cb#u͐!!2ބ74}ȕh²kjL$ jBwxisk9GE.{ =I~r~}4Mᤑ8g8w'0t`C(3Ҟ)"U2w㹛׬8n!Hmb߲ Uk쪅4YRpS2?)0Y[F=g{*^#ZRN'a/c! µsdC/zb<=VI8:~:Ҧ1Pkƺ++;^8f& w\z H3H=ӭ l[ɯ?.OCM@"cfŻd> 峻̟:Ag |2oFS>CU?|.qIz:rl7y7gRg \rsI]Z6m,J/q8(on?٩^2&(!G.'"NY!30+ A^T > {mmPwpY7¢QmGI}:D=C5vߔ6ڷ!Ki-i)fn%C )l?aMBXl j,wX~3f/7 QjϮoG<r,66x%w{h=4 s*M8wZ17wavI3(Vf jS;0mp|~{ejl_r \jg A1.,;ڂv3n(-GB=be:y3H:6լ Z&Q?z"]E>wega)d *!yPYx%yDnEZCw6/WCBHL~`-A01F|)H&7izT ʯ6ijŬG_x0k%69";n^)>6f[G $>xBÒch,=(5p*jّ2'fa0w+ baɽ?gyv2ShyⲦ."`j9kr=B1y;/!|;& 'Ř98EG~>39dT~ .#{Ju<,^)~g` R'yƎUzOPXp YB_1RC̮$=*yE "!#[qaСur5\ 䥻A* xBjAI |Gީ7h9\VSR܆V35R@"qr"º/*A/dǗ `0!'׋[a JKgCƈo/nKK!%k9'zcod0Q95c*LnWDlCә"E{-ُoW,I:/݅X)|j#p(%9dNM9xHT[ZV@d ᠜sRnн.h^ݛ>Ὣ#\>^an-@h s!M2P?^d5˸Ν &m9pT U =Y3ڸ;u7x~ȗebߙ>OZm+s(!>Kk \h /.h'vQ]~_1*0!v<^l!jK」 PMB_#(g|5. .Jﭻfhf4S)MCQ/8{"KT׋=uI1EUiY@{B9NǯQP QZ'g"U;:!xoHwL(yœ}==Sr3Ti9)|Uq5! u4`w4x~ƜFIOk-sFSz[g[:eV}{*C!Ix OE8EZbE%e.Sd+B^(\+m+@T1 4<N<15VŽ{gzwU;+ kmUqW!PoҔaeP!0dᚤpV!CI…°O%t`R^2$LU"qa*,L[t@J]+]'Άja {H%\@,Fy9dF>ezc!2t*Ab8VdV݉lR@6J9wZO@2#ZN̡FP':=)??|Ǝ^ZZv4B߼+y|D{Iȫz=Ӣ>L;Ǔ5=_ Mi%R?>:l1q2`q[(Ѷݔ#F)r'X`_3x֩1M6j耑_id2 (5EٺE &^ @6_Vb_䒬GL)EyW69M|{7a/t(ےRuT -]A=ObÕA,9~yV렁g>5-ӃfcZfB94R+C+ 懔 7f) [:ޗd/x `A sD~!Z+cOxb2_R '\g"LlP>PW Xzz־{Dctz;^"QG,fy._hnTm`椑ݿl-E~`(ϥw2XK_{ՕXA n=fZB"%+$RGYFu3ubx~r$F6=e#[DM"#a|L2}l$3bF<]6~o SX`! *'J^B0} !fl|G:69]r8էղqrOz\XjM$=foxŒ~$5@h/z>rL`:.رut&u٧YJ̍Dd⃬Xsh'35CL$b0Զ!SUc+Y;?}Gi? K6}8*e5nCIN=C޻xit,!37(0mF2J|Ct6$kE =CD7}KpfJU@OʣKoVB꜅Tx#83AcF-.. T(^G.[5o-GOFalo[2Z3&IԜ H?.oK4>H]S>Ja1p ^"O73#1d3NALgHg2NnN&ħg9D >V2oA'hoܦ>lSLjC?`Z +H⛓SdM(dg˲ӑe MOi݌c K5ƟHXP ɓh9o"XƎ\hrŏ!m|.,l1a[wYgċ|E1pVNQ߂98~> 3` uss3U-Գj.rW Ffc&!3Jcd h d'i\l=lh[9d1_4UY@ Avec1IGx[tFQGdAw`sZע4§.VOYncv2ILun=&}bI}" "¨J6]U=FTNOnc| 3Z+]F$Y Dꬊ;66` 1>ֳ&sP@󎄅2Si-,.AvXQynG =X)ifܝ>RS@"hCLt %Etvf ~01wo >odz4!5ʼkQkI4CIM$?iD 嗥1 [pn^xҹ g=BtSIKS#)١Qlf$n ǸYi9A e +Z $஁5ёշZCsÅCjs&'tFXR|2Ti`: .6 j>J/ pX\bFV҇ĝK!xcJ r"z`Vyn . m4UrscJ Tz>eM}uZ=ll(;/DJ'}h;вXuaW̆\He>s^|LAkZ:ܰO9x6E.w,SNZRtD=kOJHQGJH]:GZe(9ޯf6D'3 ;+rOy3}}:T>H*q Y_uz#;8Z45w^n,yKڴS1aOw(ӝ<,*ۏGf|)I]vSj/d^1:܅w#N$?fN^Јdqy"M]Px鯲rv{۫My4~x^0B0/[[3cpX{CE> lA"F~qq5֫h)Bp-AS&(5l Z~"'Bah:M,qw %4q|F@;3uMG ˒A3_9>*){Zug ˁxñߧƠ&פgh,L[?F(lxG+"Opm7=]X[훼\Oxk Zb%=3Hqkx%}_xfNmqV8d1x |q`Bq9_R=:u_I`n~^hz A{hIMiA7|\!F8,t-D,& (~IPQ|J$F Lgp8"@.H$N:O^E6~j &pݯZ/<1˷B:*>S"F_}W^+Lp܊uPvBa1oWCV\7[]rEl0]F74ݜKϬU0z8ߍ9mVq;z61Ul`Q!=o6LJ*[Q ܀rR" [9Eg .Y@i[>YK!P51'1q|I<yV2tmq \>wxOa9N Cej5DsntWE˓E 3NS4DdaE齉+^/3/$?!9GL8 l֯I kޑsn'wU $3| `KPoZn 7d2>iT4C'~Gyxkx^U";v[Ҭ?L֣IrW'K8DǏ%d'XȢJ|t[` V2W% &lPmx}S;PVNV"njp7fI]'/YM,LѺR,z)Mb(>wu$H 'LNuWi)['Y?#w~ o]nba?kԛޘaeF<ڐM v @}m|!<an[$qwgqt 664zr3F{gٷ43y):6[8C!h&t^΂Y$pB>w[*Ѡ*4ƺ{n (DjT~q3ɜ%h]Kgɛ"D!&'þj3o2DUyU\n:yMEVeN΢v-&muv0i֭.DH>P2.]s1"e3q!E#O. tZggkREʝ h"09? t\bw\e_2KC6¡Fk( psŮ~ ˰(V,Q Ɂ:KwOF_K |?ɥ&,;}(qzgqkœTPZ'޹PWZ6پJn5cѷ w3䏶!J N6wjgZ<]+jUX ڵ>p1Cl1_^:tky㾣77y *8ӷOgx03@Ezr2OTfE,37eNSޤ݈GZ1d?>=pTos5t4˭W OV.6Y}!iw{ݦ,vUg(8n/Zձj<9n@{{c-k2\:O~1Ag.Z9dhacǐ}İRxz7_BF*LjJ_ h@+22+ T+T&kE-@PRLߜ_JBq6!HU ƞb 4b`St=&"xpEl#9)iH G '9 Jy/G%F-xVv/c)N1@*nOYM356{S3D'͢Ku֜ghd52v~Z94h卺0(݀fL(83LTx֞0v-fM r%݁}T!ZT7?`e5X#jѴNJV!z',:s}iz|tD<=$nQRadf+L&ۭyL?ڛZHꍤqu>V%~6MYoYj5="% kuzRrSXnw\Cic%XN|\}lZ׈e2>ʙ~ɽ[%1FyTy@H}I/ f 998nHޛ. BSu魔K ?VJ0;6Wm o!T;Nȑ=vQ➧F=wTC]l_K\\z=*6!ǜ%OM*]$K6: Z(!_R~]IŞ"FVI2w)lL?p[:6W=Bqd#~Kݖ՟bErQV/{;cmsJ,!bDVm=EtZr{!gcYJ2CFN%!/Dmct sѰT >;a-tmb&d6kфhS ˝ SIл` jJD" !ISϙ2x%dx?ϳW2\Qx=*9♻u#M4w0'Q eo0o_h&z?he}&k V8H.: >!)CR|S_ڽ\,+i&-D7][ _ĺEG|WVD?D B9IP`{Ca15p#Y]Qwzv"ZM"akb,wS8nBz}rCHyWB~Ppu͆u'nZ kR9wS_Ne; d9, /Tqxp" i3bu#$L2vt1 #|?3+h7^WuIiQ&l|]uӇ])y*5#f-c2#@MYB9gsMERY@!8`B5 h!Wddů5{"/ʱ :Wd}s۷$Q:a+'Aߦx!e>İF- o( [5-oPyI #.fCOOӬ9]<䋰N\ASbR}äp; s3۟CbOZ\TLg%yg;j?81RI'A7ֶۢ4-~j^åf nlsѾUT2^Ih$W;qb)~@`r hnhI1#ZJh? Wr8nϱ Npp+Q>t-~da-=˸iG(DzX`[6Gc~%QYamy)'80UL;]]%k3ЄiJ8bH+"n`~\blIxǕͯuhd:7kxa;)^U,fdژgo 3Bv3ÖI P|0szZC,shpiݹrchpMsoYq;7AmU1B7.)jQ1T~zP <ہdo:1hFu$ G(}19#.M3/&{(op9`+9kmt :U0"AVoCyYChc5R@b8@S ޴?*UttmeZ&n!}ISxgh#02e!S45F-vn Pّc ƈ!o𶬛Q/)unèX?xTQ.-j>P2aݘy9*|mCFƐuc@ J4/~=:ywuʮe2h.mˎn~"md5vm Xe> .!F"hT3R=A==h0M -D(s<.teYUmceaB-_yus- SnPz; idFᚦR'"h7#6X(bp*wEZ0yG)ܔgn_O;ß6YCQm2ܞXYvn7jN=iGPZ7/onp ?n#4.RtӰ`/2`Ul{O?kK3_õEb҅dB4 YIncJo+ZF@aR<eXO9ړ[?{oaQ| ّekV}pczw+f.ɂZ$pەFbݖh q;j̩W}(@]W%χR;?sTW1ntwGN0sMg&O ƙnI;9'-IQ4?Rȥ#.+æ=P5pM-Y!woz I=&ڔHD1)bmʧsLk5 $&jƬH:gBXkuL)'66b7NSB50%'.V6ǔIhPLiH$q.J?^f0%b JDݙ-`f+oӠx8 EH4e!t=obE;8SxNԦAbkRv!|-ݦG.H?fwv(i9M$۽ \F^28 /W1:UZA% Y-2 9n$i&H?\K.dͽ %1Gj_*ʗ  Ƨji'lT߈u(9)/83M=;UeHgOA 9M r<#tfQYCe]}}k'Ψ(٢OV#AB~K+?jtD)ԜÆۚbAE$܇7S3z*'驓9OgK e޻oxoG f iDT5!хİO=O@KeychEtx֚k>\1@U*3DO լBLKSEub0Hot F[ aŁHXam1=9+ zJ,+5^9 6(XL"Gbt3fjE'j˦9\3v*Avst}=huŽnu,Mсxd% c_e<ySGO5E?lUjeE?lՂ'3McPSKMG}R[H)3NnwlBW{%AUKD<Cp5t1}b[*ݪ*.*u  Uvj'oܫPᛪ=Ե0nqlj#CgsS@Yr6<>*%2Bi/):^VբU4(-^k(OpnɧҐZjh,#ï\IR#͍B^],J>?W|M3TxbV/IL X85ӌ6k>gYtԬYMWC4qJ,VJANy' lI2||4!f\u@Ȑt(SaC=›)Cbdat?ޅA!=R[=fu] 2Fo'WQ*R.g 2dŢ!tCPbhz &Y6EK[& =?o|Q3&Sv^%gf]2>=e8x|WP1i*o{ Ine#i_y~EbEKa(!ް.F*jsLا2,44YI.YJMȼVd恛PjW8!{D}Sm>E)@*Jmr*&0-rFI =)܄=n| |V0`]6I 6V& Ros!fB\˞q׺oܷ!UHm Q)&+ًuUL/D7fYM_G$<]S N?H .^/\9P茾0Q\-\f0 1 {7R FW>*z_2S=!٭֔->`CQ^h0Z NKA]3"-)* Wy}q\=-ߏi!ٹ+eߎ!Ѷ[Bw({q$~(<6lK&#,U=[59 THȷz`zR4Ֆ>&xbQZE2\]Ջ};Eח@p&y\TKqLi:˄8{*FZζfwY 1zh'|>`ru4PScO$@h*]#pPg!_}k>J/OŸnO6tUty1t /uM@ޚES '1^g@I"5H%9'2u$z߷D15 .G=3xQɰg4cL87N(ewJ0) J ;Z?7[}V() 0#/I}76n!V]Za\q_xr핧Z}WRh" ?BME{&qYd"2yR7@:XQ,ӽrD_D`es,xMyC>ۋCSedASFQo< 5VAEǐЩqx>"'Qwn6q~OȝQK^By jE9/57|+߹eQL> !8o߁N*}#miU9fKDRUjH./?Y~oXRdB(Mhj]rCH4"6 $_Z,l4)\w2qLZ}` w5F.4e^2ܤ{7 74tx Vw ;]"@UɌڒ?v'In@~W2xW2)w;O0oC'G-/hP8T}esP"0GI Lx :q-m (< &KZtsi[|P W<6,B N5Kƣpw$>m{̒!LohkV&)`{n7b@գ ME\ p^SLgxo}C:FR KQ^'`,@O Ѩ%%_-BZk먘{\ ĝ ײS .|eFy %CUT.xJ(4$Ӧ:0.mRo#F *a5_7Ѵ}M.:=4j,&jD-4۫SUפYGުgI:^:zI[0 τ">Vr߶;x7 t+,2h*?*Is5E2g%nH>7ّrL6`eqvcjbQS| "3!G:lTR\ɦekU>8l~`4u@*CJUͮ޿&Ŧ'-=`)= BW'";쾎售AP1i]& ZxgW F:c1pC)@&<?]g8icQ/UsroEKHwnsw$BPT`XN2uV˅@*Y!vTS &*C3HZ[-p;% ?F Ysֿȝ'>.(UCt<ߣRXWEd#ͥ7FJwI&:x tYr?0R<{Ubvj 8v̘Ĕ:6=(?a_z:Йn2qDÂ2/أJs G*dy6|= m [̂G¡^F +24X5T*|H,x{|(jh-zc1V/ѱg]5_LVZ%}+#f4+葰>tJw}{ΎƲ-4KU![}TeH~&u@J9n&;'u(EYX^"Fmdgc_PlR0(Q\H͉DٽNLkD*qݪA-:WC1;P2ЭFYFBjdڼc.1UJ'呭w.*kK]'+@~{I>TҢM=X蘕&mWol /!`WGz?̠ƛIe?ܮޤt_[VhddVphc%07:BuAی A} L5((~_3;f>1jHHoF~jzw܇SOJK`5VIhϣ福9t*φ:~D*Qw nƓ|[Dv zޱ/B^:$uDn헫n wj#^q{"8LzҿnTm()xֵ߀æ })58y( $!Kz+ rȹ&` Rq7r~3qA-u~Ķ-}*(gƠ/D+0ZU9H^Aa/ͰӮ=2@{7M[*ͨN^;fN]d\`'HG,6|a  JTwj!ͪ+j@ua5;HzCߡ"[H~!uмrJBy5$/_VY}OnAuZjODtyqlq MxϞ HMx֩追A}ʏr dܮ^my3K7(Yc˪@Fl?~eIjcg3-&i?FC wkق tb1kW%B;}"]ž% f8GqGa/umEӜ}*qح82e K=qTDOY~ǃ/c `RG"VbYq(Ѓ_dP(Qlf[NGPb!K;שB: Efy9TCF#s6MtU dwQ {9oIj"^8ۡ:B(cY<_~R yqe :`رXTC^Ɂq51<|1zoZ[dFkH_"anQgmhIaP@|T5R#{L&V %2I؀*>UW?5~i~;Qxv{f,݊8h3g֧G ~f̷%fm¥u~wY$yt:.FȤI<9!2 ƚΖ?-vN/jF4Z ݇^f5Y?Dk)mkuNz >zϛ&O<C1/֚B 鑒J {Fx-w)FɌG p,w"u&%Lfmc_SI QJy=;"LEPr\B|إZ(+:3+PG EܬBuL‚ʯ<Ӭ> עrWP{kGVE\h!T0gk;zht53%*|׺9d;QV&6ei{lm?YMkf w~(*"^x]]ӌ JzOaR!]D1IGσ~]轛.`&zX$Ύ wß.;]W?_lcHAb⠶&~M⧎7k8Y講J; FQrȴ2cVxfOnHCdY. p an+ՍmvT>bZr=%UR}曀 Kitbs{7 @`)'L~)_tiI1noC,痘ˤ5+G뛭gʁpGd"[GCh1FCC%+Q!U;Ż⿯1 .Tdrл~!1i%zˌAe{mD<`N,e*w ?_T ԹRy}:dLe<Ɠtc#MK|ʔT{y3ۃEuSA•UzubBa[tJ=BM eX`W\4:3S@0F!wVלҴh3iW&AapdUHPd +THvV=0C AEQ 5/Tx7s+ S 4D3\:`~`,rdHᦅ:=cUch]sd5YЈewῤ^ 3وd,\A嬜wU+ۿbe7~#v CHÁMiוGܑQzӂc^8_x[fԺy,k`Zg_SqIќjڷУ?pD+jI> {='*֒|n$t$rfɭ<S=Y`寨CH*5VMwm;kUH:x-#e~D37|F:E 0N{9p~ ͬ%>j: xrЛI)}[CF;H cv&w8j)48k$ ?n(lx3[鎂rOR1?`r׀EKyp% [Vײ3^p3NÂĞԺ؍0rl~$yQ֬o{[[f1c`ٿ{_('<KPi ~Bg l] 018|^#zC#ǪUdW4C=40Q(~:*W°m㵟T3Ɖs5Őa2ؐ0XȼB2{0ݮg%kH>ʑ>Ч&+أGg&c:ʡ.aqB V R! _\(ȓ4?n;^tt|@j fձ5hWo />rAN[nˠ1 ; &&jÚ!Sf\{ʯ:נ>%9<̭|AAK߷hk R"DjU&èI LOT_@[:!o8tq}-8Ӌ~wHF⽍*zѰˌ5y~;4K%}V P KɈoX|tF3BzA PIV`/"*Z|SځH{ cqt߫5ڻJ+D^VwmY0.yK%x Sa=⽤48:W't@~皼> ݯ^@_]8X eU*Z>9;myX](Mbo{~U\h<F/#N猡 q zh]Z֏c0f@ )E dd&q]ǐ+MX}<[ iF䛦&;'Ls%p{S%*L~lB"Jum6 PDKj ΨYTL'ć^sb;<-&םFrY+p: ͮVR.2F8,t)9 .$}ݟ<#&F[Yl.kߓ`,PӳFoɌ=((ծn?Xc?FLE_g1sy2_oCCjf+ 0.aV@<3 GnAV;iMqܚU3<L6 v5sNH0aSb3wT]C7xtS Ьx1±$E.fBuQw1{:u^|PbjH޺c0_9:%*\Yd-3ƳZ $)I* X Vf;[~b7I݇~ K ްko-㛔*Y6H:ztXc\C -({SPǷ?٬O SGU8_JL1(5CtJ(6v cVh-9T7eZXkveF6+)/KQwX Nh'owWk͕ji ]'vѲ_BZ:-kҔ%dpMO-M:ct=0JO`D'w.'.J+Oppׂ|q?v"c 6Q^KL X_()cu;Q96`;,9V<=Z]atJ)oGŒǖ y2|.Gv{U/r)266&Mlp. bƛS7W}1-3XJ%UNp8!̟1Gn,1CLˠ ĴQu!u<9Ot0>.(̥&+kG~BB1$Wgab٭t=z Amhmr~/#&-|j @)u#PWwA3v{[o/ŁrwF4fSޓ *R,vՉ`(wXNV;Fe< lwG5:,UwpCͥf^1Oʅ֔ k(kIyt\jNtJFO"W9̱PNW7,C7t_H4-MǮjǭ'[|oFdpẜtЮ X:Ɏ![d}%53<ɽ0@U ;CoRUi2]/Od—󃧚'BL|v[6TYR$ sӴz'8(x'Z,[Q_46"lX8궽7ymp#׶A-Tգ[BиxB#m=}9@Ei-l'ંDߨ[9pg!(CB,mރiwΒ6"l2|;٤i|hwUKvd#P߱/RZ}&rZ`3³T ң{`Mq&ޚtR̤X![&9.B즎XC6Mm:ۤ FhI-<:VP nkƒRr?}Uv/,sBU/`ܢ 3 #vc -[jwlzѸg}ADs! f'"HKl^2PQ_'Ww}۫OY.rߺY7)>1(,N`fSG~x~}T^դ.h ,oI' fs}&?:4E3{ k&B`* -""jet",M2rӑlHnG'%g YbA,?+5{*1| B2dnr?h}Wn"d&ՒߖNe͊$Y^X'ЅyyCZe-_T'A1]c 3D K롔~:WZdL%CDT٠d5N}I&YdAX~zfUxo`li9bdlgHKC#6L9xՓ!k2QB6e SHaYb[( uj |F+)lZ)8Y)Jtr_;ek3Z%!Y"G32XI7.jmGq'&y|r7(^,e7%LM 1+BDg  6 g?<jUF\PRA~OG`?V-%G 4`}Goks( %4#GbZ3Q4UQd ._J"`Qh7a3k8QhSh k}K*X~ZM%B{3EC5,3u_@o5Ti~P>O\y5wɋG8*k15eXK a™yZOʼJG+l :6D6Ƴ.r僙9tNݵ!Ӹ^q!@ew-oDw?%e&%2d0BΌ--Laq\TXn);[߆rpjR+.c/S~ӯSJ}*$*'B 4Q+H]kzy!u?CBő8 4=7}@i1-Lk徦K_vf!02մ*X+uk#N;[t+F5 %7"k`nq;AN90/{Cl%V_'8*,}y~{AبD~uŹN:*|5c&(CR`u^mO 7`w`oON"BL" 6o~S ޳g[qWhE7A±Β@nى>%I{+ˆgOwTҺb|<Z ߢp% |Na!¹e@>>,Y,FT 2-m7z5 ê/ ٓ\ en'gEug9cRCJΗ쟚D̠^Ln"*E{طcx=ѓLO?&c im4k:I^]4͢{-r{n؝gRMܖq = Gl9"~iި6cE9S͚|vaOd F/vrA?ڗij Ӓ:\syŃ@mxO,z3\/+(Xp^Yų tCXX!Q~$ 6lԹp sv6 އU®rcUU }ĢbˡFg#/#( z$'N+l/lW_ 6XyHziR[^q{]h"GIN1 x}xaVue&p Jy^ˋ2Ivxon\#[^S.[&/h ܿ?yUXӺRX(J6uILh2B;яUcXVI.A$Cw'iX:.*yb<,h6@;bP@pn|hEa 5P6~pI R1&- #?\ɒuPi_hAr\ ɧj:\h[<=d1fx|޿Rރ;MC FLAuƱ\W'ZIk4$8t~0},i dԩ/B[ƭf}lyi8)\Hi&2Y[+3 aK֥@gIC׃HE}h6@TN>Up':g|9,2zI1s~Ͱf^D>_>Ron8F K@Q+:7b7}g0B*L.eEZ۠@zѹۗ :oBȸ"kJ:"VQ,elͬ>G@蜩v2B8UTyg$ڀ>z񡌡Qt>܌8RH޺c&E :.HiP=A'x@f4u % >F﷚޹2O;ts7z#Q!U=r,pO(&mJ"H9˺wBwUyY"a֠qoN0yyZg#GI^F̄HOӉrQHE /) OXvdJI3:SAWݠC%zۆX`,5:qxk;m 3,<1E~eN V҉dH堅(rwaQ%ҧ[¤ )Ũ4.~< *Ğci-"/2dJ5ChʴۻN/g˻7gZ0F=+&T=ekˡ%Wdw LTv&2\|T Bb9FǨu_Vc^Qݨa? S$e-="}DA/XR0̖1LF@Ʊ.20FT;Ce\_R|òvԴ f}6,t }KzD#45C&t/8_VQ"KuQsNoU.nN@Ղm#Yج!U|ĬǝE{c|vJkk#;zӰx^v XƜG||kV >S.<]6+cvg_dYt<+!v78̂~@^5WtiBN BRb8&#DvŦZ1:Dв' hϪx:1%"0ܮr"Σpή捫Z+KHu$٦ǫ2f2 (Y'|5;AVxfk{IjmeFh<6RHPV l[:e<QLhQ{gqt΁ E?uz>$*p͍G+~m:ǿXx$1Sמ0I~ۖv$Q;.b >tPMVaow7L6-QcE4Ω~JR7N̈́etvRFf d Rv~Y['ǩbt+P_ 0Q"*SM"D6 qw9'I|Ӛ\9Gj@z>=a++ˌJ},\7*뼂6œ'DK?P^?lEתl#_z_,x]O-6t62v>zrpgUig)Ab&Y~)%KΑR\ !udѬ1.{$M␨T}C ;U/< GGN+0q;ڻrnz w܎%.J f:v<r"Wݵ"CS1\.B=RUU@]&^/Fb~Zu!1]z>&Ң"rpO;CItkdjA/t۱a^pUF~3y4[" pz1=0RA#ګg|LFxx!O3ܣÄ,,{w}:D?I9scY:.ȗ\$ ca*-A演+Տ!5mfhZi;\ 60ZtC>iW.7!VoJO`;tǟ|롶c*I,rНͿQoZ0Kdm*沉KGŽ|HSs ҵgwrQDڕ%3p }xs], pwyӓF{U]3I?Y2̧Q7ʻu7Y.+0}ݫ̚XcWD_7oDh{2o!/PŽ1y y퇃OŋXOjwv!7lķ=Xgb@Hj|GB(ߖJ.YJ Fmrx96AZ09NS DsSjތP+)8`> Ԃ 5kⅥVhn lOS;)ʂYi>$15銕աٶr0é{ښ1q?V遙mo*C"Лqd>(|a*ہ\f{]:jjRVRo@F[^qGX7%QNׂ<`ߜ n Cٗ,g+0+j/rg,]ng$MF[#}"1-}<d|iX($GWr)cJ_pTk\/JH>ӖFUN-rh?iꋹ4O扡$*:o)xJ eةuy@!/x)/L=?kP*& рQHVx/1 \z;nf4k,-@Z IkKf^]g*-A<woz@4Ip烃KZӬAO^*I.I=mB1Le#,BH }y1#RF-S) 9m](|Yeȷ%Rw2)"H[mzL(uM>8¯WGzVP2yk_ \B2dsKo Y~BIh|l|Y?S~/!y]UJ֤ʪ{'ʴ<6:jkeXC#5nLX/&fV }Oΰ8b̓8̆'Ro6+U>&2V!DSRL1qB=6houJ BjG*+;c )25m@zy|+:krQSFb^tUim>z}T n/qܶYl`B5\; f$!tZQ]{ss#60A̦ZlJ WmV6$x,\F?gֺyH{) vi|(uBٜ 5iT]azrhlJԟA9NI/^ ]̙;q CmT.whKE 1pP*ոF L~{k1Ijz3DRHQ0&W8}WA u( :!g$g [Hhd{\kJPݭ6I3}I],GJDi'`!M ڌ/P$\"N|0"dW^t'JdA\(PrL#8y ޚ*ٖq5D> gԐ;S&$BM%k#客H&hx0՞Eѫ`Huc=$GdRN)Ȉ2оw (VC~Np{eSA ziܤ&\b/|yۅuk>Ni4hK(lS2 `ex hN |F_`3SOU5 BJrC|ZawKwdUߪ*enȣ WǾ18),,sK,>*f##ֆs8I` >idjHOIK묅V+P[`:mhfrEvy }3 &QRd:4s;H:NQXs(q!W` N:. Ul=2vZ:4}l(IWFml[Z{پXjC5&=꿛}L1Fbc;+27Z ߬\T c}10X5"%q?4hA e$'Vo!G͹ICUjC>?yְ8gOJsS5qtCd5i(s7X?:][`\%qͽ`N^f-0">ZP# rG@y o5d) {E[8M?}7'F$<i"1{ %@0&^g<~"=a`|'6بb_REB2tȢ}UfQi|nO.$N( 8_ ''NW%Cn0LD؆ XN/} ތ{[V%wp7sl Pb+#{42VZ&0q_5_ѻF5=G Za)ŝt#(Az$7{n`햜oκ^e`<:)=8j^NUJt'ڤHq{>*o>uBԣr :yxhMqcK1S ~u*1]hYkkhbHЄ# Ē( `Y+{pE- c G41Z?Fq .KKPg\5`-n$ Si] (_uF\Z"ِ/e"+^#'{ȝ/HT.i?tX  / /O "[ˇ6YuV(/,$)t多/=W'b{Ncs$ b6\j[1Ȓ] Y~1SX J2Vu˩%:-$"d_L*:TjpytKpHIALi6Db^o-rP* 7@02k1)[ h6sNPZ#<5ZF`rawPebK/ߤi[X2{S5@R,+*\*2`OUB|Ґόyxd4|ɫـݩ.i` dv(;t@St_+Ӟ,wvEۋN=_xk 6V<$ܨ!a.3x5óqb"@4`.~,n9D)pv*xqʱ8-Fٯ}$PnK9d&`AKDx@B6rfJ ㈲4+cHbl`_Ygi> UH5P@+f2܄}v.`#Ҟjw0o67V*@gR~b~8 H.3aP& Ia}gWtkW2Z+8TB\E}') [&?qʼntOeYCo+}#-|hPHt^/sZeR Y 9b7U hm: R .E }MyW~~4wwZ׸owyו^ʖ 5)9IVNCO1B-Jx&xҧO@=;YjokbUX=#ۉ&J0+zs-M9^. bql@q{>ᜢQTqDiC*"@KrrEO0f\4DkKxn9*lQdTgG _oz3*Lj> "=?\X&ɯ u7 1I 1Q{4SjKvd߬[1mBnry- T"v۰Q&;9^-pRGZTg X ZcY8`QYf7Γ/Hy/姪qQ}>ezrbB˛L H,sGwԧ9S6GlTYe۵g$0e'Fd]`K(9kL}~3e֭jp_ /ыKbdߘcO-wO :FSMf@\rR0eBБn$ђƮe:nSVLc`u ml~8;o(ܙ|A݊``N}ui)/AT_Y~3=]$nyh'*%yn;r5.X8 I^GY~D>/'b(ͷ{DB k5~na@~x@ULlQ%bbMtՙf?euw2đ~AIC7F8CD\qv+Z`ocPb m.7U!S.q/l-G__&mj'F$ 3:.bt ~-o\UXLj ;Ę<Ț6z3ړ.C-~!U.tْenF3uQ,n6h(VPNVTi?2*`w\=|R@UqjF4/Yo,ـzcy2t ji<2^jƁCiF^ "Kf{".%7vK#]^!繗(X +Vy2M˪7xy# ߿jmGcL˰O?L?-?,f+#a3c/0P1~y!J'9@akq\i=߁Elo#qRO&rm6l+ TZj̳'[4/k!*.4u"4hMİ[PƔM_rnRWXK܍ۜ*=:64.unxs "ڶ?2gѳr(vxWuvQ&@=PrR<*dD"B^0u%a5]b?qųF'g)=TYf=2"8c2urY}HhGBPpȈaL0]y-*՜躛Y1@{'zZeUWj$pDJa7FKuFaˣ/fjIGM "A {:ו|յ*+}0,eg{o7l|Bw> E&43oQ`-5=ir&301XKbXH,M0-ԝHZۍeK VKy?`RXHW$[/>*SbD>ꘔ%eSZPlu;Lk,1::ԛ P}YӖ /_"9﷨m+2=kt-2! DŽr€(y<\ ugҍ䅕Yǻ&2 ֦u& =:#@Xic-K>(yoODn*оo4t.@V{>w@ q5. L)cX`Q>Hz]^ r (yURe~^O/?gױSLiH%|-ςډز6uD:>S PU+G0HT}xXtoaB'`PL9ٟT\6QTX䯎^"(=^kJ^y cR4y"ܯ>V}ٱ_8i{8`RYs@ BA z{CX Vor:׸xrEGF"/L\:*AF;BD < w]W\6upȝ;p~jbp&_:;vJRA~YfrTt ]i;RGBBALrOW k]^e)pJmFPnCxSd9Mt3kK>/5i/N R{pʤ(X!Jl8y7|9mx([g&Tq^MpcIBA]:/W$2Q\YcrJ'º?|%4C7sF"05gAI6LyB`-&hA!(Yhn|0X)NL9/'#a<3࿭}&9DPKgEXbq xn2'S\6I(j:يU<>74s>!-k9'\^#E։I>4[1bR |``wcU}W":ZԿ~& α̂c"``:j.G/?PG6ԀQ0GAtȁ`ԳWwu+P㒕'ߴΒPb԰(M!UfNOY /B~y!y@ 3B('ړR;X \G$v6/ΏX,k2U\ўb*)* /O\+Vzz2(~@Fy5 lYHaz%+7iȟEL'qhHTR}/p⛜ UFwݭIJΗt3HXy(Dj}"ƌL4Z2jmu(a8AxZ{B#o4Nm(RU*n*=N]Wi.;Z9Я#FN퍴Qs H21PY@3ēX:I x&l<^OʑNUuAK OWTˡ5ѭՒ* 1{Ti$[zo4OcI.]cI1";[HtT&d刐135fDm D#nKzbL8FUSj8Mď^iS`}gZwvP'ՂRvv॑7$l6UuU:v~zZ&C"Pgk({ّJ""͌F漗FWV)=r{:I JBNc£E6ؖGs>)ĬOY| BC7P/(e.J !w$)JN) Lh͚X BحAN$ m[kL&0ݶQZl<tBiE 5]G8(H)ð5lr YL-ozLs>΋_َFE{Z8baƵΙk2sX99O~96uҔnҵ%x=pk"Ķ;Etk$gy2v[P72vzm΃m0#,(x\տD@Jeܔ؝q1nDkX צUPJj)mYC"6B lDWrJ@h:ALLɗGǞI;*5#UK3nػOF?gCA梃tcUpζ`駊]Mi)?EePV(9W-n`;+|Ra\- rw y-'W]R &_6*xp40`>TP|c_mx3S`rP64)<ğ\v !tP@7ؚgfTBtYnCe򚴉EMUb:QUx˻9chQ3T Bn{PЍ$4ך_">D؄Rww8x/.0PZ$笖ol}q/U5[f7wAZnsHvd6ڄB_Yijt@1~EP.L)qɷӎ: &j >+WczBTfaް}M?r7ebGB`%W(ɢ^E 1'*k[ڝ756q}D~fPm8!% 9{.SWp/iK)c(dمbI10ƓB'PE+WJ{[p}b3 ۸.\hK'ry}b'o &8G1OeZڭj~+L]]KL^%"$ ҡcv{<1z\$!@= &]vr\IyS#TJOd{{,/GK#{Z|ߪZJy,?Z碬 ly\ *L@y: 2`3kALYY.۵O ]~V&:o r3z0y+{QBx:* ?\ܸ, h|"Pkаvo4 XYtRX;3.Fhy 0 @4P-s @yQ)&j}ID)QǦ)@J pE:Blm o_<s8eO¤O]zġ1mh'.r /}dbO_s:@o>(5(;@%K |k%a+ESD hUkh R>dʟ<ύuWqqwF]rgg>b(dϕdVm`6S/qH݊;ՆBF3 j!d1"Km$L8=]^?Ua8k٠q-=J{ )`XˎHHvQt/]Inmu^PR:4 ^ B.).GO Mc:F󈹔ݗ'ǿQ",eO~SML\B/]Q\=`&s$ߌ ԦŌxQ\j#%;svd{3#^ѡܦ1ҜIYsYDިEeҵ 8Gr}{V5puN6dԝtA$Q(7 U9){ꩳNm枢[~\QȁgY;CVtߕx.:޿ݶA 0늲 ;HT2|G/Վ#Q'K6Łilp|o x W/j+TMҤj&&i{h9&d|j6,GȎ,jCC ޏ|f+8%o\ۃw1k0ƞ&qMp"9Cn Ym%,]66z~jxImղNW'Vdj jD i'1 IP Ƕ'$EzWqjeDojb~Č806"D6΍˪Ɇw\>FG#4AXȅJzZV ^tȶ%qփQv[χ/(iMat`slO֐M~Gѿz>7}BaA J[ C~d-hZ^%vUjXԗBn_b9|ϯrzdAeY Yd 6@v!LV2]ap!" $-#@S>fLJ`[`bXn?6LU_?^i={25Q~'(VJbYGrJ+nLFh= ~ t89Ebw ˕WAM}\XPO^3iJ.$jcK1c4;҆C>y :ӭJp_7RژSOWgY0 :' oPX'or 2vWt$֑YP[Xq='~r^-̈́Ҭy!0UIiQkP- %Okk~$ !sjxたcsCNrr[| \."؉bQћE~jciEj$DZƒPgpY]g?Q)cSYkVP/iQڌ/GC+z6.!{3ǫՏ3YYbZ2D'Ŀ3dhlgB4.yn z<Va*@k9 ]H[Sv>4I+zIe/ޒ#!n!iF]]r.=.aK3fPv)FBVoG= g6oXG?焅)leh-ȗZ53zhcHa Wk\铥Z^q{p/7h9N2.kq%}$i!nʏ SR?Nh>s6d«6/9YwS g$.wo}x9u:z-ķEɴz7VGz⎀~8u ~2P\u zӆkqH0'lٝLaR9Ύvz3攫`@;ѿ|Ӓopsu8ߛ#7pE)Wie#$u!bozV|RF7'5/;ؑd JEIC^>PC' >g[E^cₒ{n'Ƙ0cHmXLc{ɍep=E)]~.6۲ ?+ 0[dv̓-(䖏ש|zѲYC*LA#\27;زn O4`cYi0tRȌ.E~|8!.HaWLA8>fc\@s JE˼rO5͋ɡ;V&2KNm9yp:"h6 3t8JMSeoZ-hnNw%__B8WĦ! 5Dhd 2pfs?ԿA6W#v;:i #w LJNFLWP-#IGwg9VԢ͠w06xg4Z" ltА9s\KI`)L)X;  eND^Ga``HUt,{! Ot`W}8iM Ń@o]u:O>7{ϵI='t1[ t3 VEuPQZ?q|ç]r-m4`J .Wo\8e y*™ HS*<Ȝ?uؖDqYY$ %IFd`b 2rZWDۯ5<\Tf.d]]e%uC#ŝ}kӿ@H횔(°y}<4+&7hնЖ!fUVdB/OIgLY{ LS4U9 ` kd% PMw&sSAXbYfmbJBrʚ/We>Ρ#ɵ'Ȋzvo5ff58¦ JxV C+a?݆"ӯJ͆D?>221 ~ɻ SJß4P{+wttAä&{*ڙm&k*FmF'Fiqe&$aU%WRx1A :ߊB(qab'PޗMyhZ}%rKwyFc89_}-Etڼ&Y7.쒏Sݕ\-f_oUྱ|r4o meu4AƾMs`;?[FC0탳;éu[JZ C%4ஜbևj!8 $f&;Iݓ^O bQ` vfYXS轃Rɰ*͑T♮WK{c ղm|xWlY<ak NZ%WPX߂J+(۔2o7^ڙ<.raw.w6.Y}mQYN:@պؙɎ2 &\9cٓI~ yU9L1|"q3vᢁq~WGRRVG\'`1PeDmbUǥegtYGdi`.UB9 r`&$9&~3ŸH|ו_,n4_Nn$5"20P+څ;U#W-OCt50Y4ŻrK9p3TX% ^R]+B)(~HQ d'!qwE)Xk1@-^Y|) p`"*JAr%j$kM (F-R)Mv` TɆ.~O2NR҇.=8kBoߧ&zSwIZ{ɠ.>0%/ֻ\Yۮ%_|B3ok]`iq,M:?n[(i?4BJ` ;y"طf\5`puXd 3Db+T?(́1Bg;Tv>)Xv͆{aC.a]B t27Q2QoUis5"AĊQ\0[i,gfS>q#DPrسGiZЙ(Fq$!b>E1".}jP˹ve(N 0PܰߛjnljGL{~x_/]LWP{5 ʀ2rQkdXӿK9mo,E$ =?NF Asδ]v_??p 8CiAq[Z|zб?s iyꂝE2{8a$MPROZ3 ;2 M9*"k [lrhMϵDse엚WS\.9'lI&؝ݕ||MlmZ?[UΕ # "| bL-t0 Cϣ͇P#; DmJ2|dWt%nW&}dx^6Xx&N:m8cU%C&,yAi%!|g?_ROah{^.!ڼ5yjO<(÷61\(OE*+.%uřз1sqgg%*(,ş41nxﮒ0f  ppB`KJs1@VZez7h1Í>H#ĈGBjagCV"4-{N+quކ&mh ;&$L)`>-MvC%ל;~Q:t&S)p|JB32~3nZS,cʋoIOT?;ҽIPI*ΫjZ>xN%V )7mH4n_Rֳp lœ3 r =y찹w@̭"s|j~Y8^a?݂LYKu=X;-7N/4$.7t[_{Gxw_-ꂷ^Q"'V~dm K6%{Wm샬ᜍ+hCSzMݡm!!l{4:*k\JA*=!zÂe{m-7 F~`0j$ڸGTْڎ r\d>uhu?ϠZ];b4++Ԛ5LK7$ y؉T>Fb5 @!&W'$SMVv >vUHVGٛK̟ PH A,hliV=T6A.l%HrËF:꣼FfH1h&'˧Ni}_hWw8ضO$ctVaR0dc.V yG3k+$=}*!Ţk ิc<3^h [sdn? y޸['s j^6D_)(L~w -k ^N%, dEqly]ѧWJcl\&q |UF<?Oѷu(dj(Q͉$I~'E:q/cNJH89B25D .[+<(w.PRL|Z|@~ſF[0/ΩtX=#[Ur-@0PZk@3ef=m/̌<S9Zb簏s?N(U@ bpnÇ&X8+ntG{v(x 4L0o ;S$%gb964.…6ݔl:ASx(ӍΗ*h6bT0؂};ęw^X1!taTU|5nY $o߼BelybO\We1rtҡORV ^9 KjՔR;֐fS=at8ԩH "o .c0ww ,{!Og7ʚV'%n$hImA/f{Gӝښ5S#=(P90Okgum4x 55MQvI%Xq#|JLLϫU]Ȼl:*ܳu{ #X@]Qf!2L2DJGJa|;8[0 Nr].F_P .C5==#nJ5DdY2mM cǾ) DAcfeuO*rzV]QȐT}63줧9`DwivdP;i/MhPt?5 7cP27Ԑ[PO P]p|7aqDr &["zwz7a9^eܲ=IBāy'uB[jsy-qy}D\ZxQ^>Tg,δ7pnw@:~NZ~A:/~ CYDqC;P@''kȮdzKNo*|Y)~EI-_\]$$3{1x nz]F= #a !CL#rQuQUi2v4pM`-YWKk*orlNX)N^֭JW oE\m0? r xUPeܦ/$ʱӲ?XL]AjAX&3PBw859߼cs@}ceB;| bgUgzAE]ˌg8 |]!{,pwvs(3o%)(UGa^>wEm׵v-A֌ (nKl2,ǭ0;D\oUCE,j.;bjΑ]4NK£"4n*A{e e=X#ߔjUDb`fgCJL~ 5"NSUut`4B] :C8qqO~87@f!ȋd{5M(e d<" ) 넎r'+'(q nfk㵪2tMtU^Ho\6c"R(rңGg/E 3(IVF|P:BF]\c-)6= s+*jw~\7isQ[a55@*NI/l)J]cdP\$(}6E-@,N=q~$=t3iߺț$[fm4RA⹉L"A}gMWJm9Yz=Gjk8&VŠߓy&P) mP^BL൵-0xrKJ(x*CFcI-mxblO4o6G0jtge8k=װK @sQa*K!9܊$(Q.ܰۻI -Ů~c촢Q2ç3/lud$hL 妀]u:}SHsbbT7 );Qn B3_QR9Riw8WSA<֓8,;HTHG)pV F>LBx4?Ϧ ; /$LL93g[D\M.IwJͲ+@xEۉD6FU3X9*+"yY@;ڡl^)9pCVt#UGtv"nH.znqjUS/;oxݟ'KDhPei(ks>6#;*혫 -ETpva?)(>"-TH1FJBF"y{ʯ\{{h\( ad[G. ‰gmh9aQWKd/΍h_PXZe7neA7.Gr@f*²wiөhWjO{`SdQjS93͒~5:XUЪl DN%ӕ0]YmvP esa#f"AwJ<\̉ ;qq^Ws6UNϷM>ywӆ+G"ϬBpvqn8IXvwf+o ydIfIP\C`Җ?FOx|VZ;۠.XµׁGW߾>A}a&$ECFia?MVbOyOT\I%' \85pOށit?IB=@%=-2y0.0Iڴz0ƭ#>z ]B<qd+y!d(tq/ yl>Q Y[i(W_ +Gj/Dv^{"m`11Wqʀ~RhՁ|?`ocu‚b[c hƘ1Ia8F>ƌ9QED^F|tK6YV='c`tWC[&hUJ,T7M BI<΅@&U>%P>`dIjeSڥQb) +UD__״;˭ 0AuE旙 _#nKsqRC^V?';[ pfׁF䏔P}h`҄)aQ.p WvMT՞!}PgWraiqD.hmjo_~Z'3: XݽON B ^B&' ۬mHZ^[ٷ(G/Y P\*82* pnK {DqBcx|uOi,9Kbf\Ntno`x/΁UaHmTl5 F# $~E 5.}~*;9hu#.kZv>: z^T4v]퐃1@1ɒ#Md{rM>@;.~ѹMcB۫IϟҜyosoy2>6hg%1[zL`UUpI߰REx k8:i'o#?߼ Gvi͢XHI@5gf8:GlraC硥%Ϲȫ92ΕS9Ati5ȩRG @,iE2.=-;.[*bĺM+|zbL;X|Ĉ}L-CqKCfl @=!3)^!mO^N19[:ispVvjwNq*B 1 įP8e7;](2BuYׄ`'lGπ9?sk>L 9"R62-n]n^ tW.iRpuP̵Ф2S_疵Nwߌj^ 'f=P|F!6a؇9^K5fwgv}-kjOKyͳ "?4cdDQR=E8*oM23b1 ;TAI&QKf x C &uhO/y;=nod2s85'.AUVG(e ZD:N셜ks"KAjY[{E0hm{ B`))kޡMXC0rGI& Q u4ױQ-yNgT 5}+W|xC%ɵӁ#ϞJ*$!44F$-ym`TAK^ 3#tQ>яGzn|/;auSu4YMX-w8wuGnW^NmFM| YS͓L<LǶ!m8o5I-^$"DyzE^|"!ysLg|5hK/8'FI9#PP9,oe_ʸN]*ԨU/3c)u&2+?ub-^~єm[4D&'>A{}^ʙ!I` zC_I)ɀmwh/SF@qX%'*}e5Z!>t$U (B(i KJ[qN[q"#`mhO߅'yzx-Kgկp;i֋ѥ̥_fԃA&~3+=3=4Q}_ Н0= sWl BR%kK)cVc`o_SLNz4/eS1b|In` ]+哺ͅ)qRn1rpUj ;V Eŭj|bƆkl|V% U9a+ӇL&@.W.z/)~o3 z?w_ pPH:ieZ̬g@{;NR]k8Yqڇx-l+d$n3VAg MDLNyȸyosozCxXe"ÍKݴPpVMtQtvQUsPo2hHT.Q^^T7wO)x"f]HZO TmEl,P*\HX/\GfiWk0ȕ!R/6wzb0, ԰j-5f11j 8XR"CeSo6ֲޚύzg^zq'yrŅXƒs%Ԁ F Ra9 8}/Z5+rTySC(B/lҪ1{g-Ց 0мL<7VRqJz-6ǒÈ},F71Sl(]\e&6p(dӁθ准yA%d2 ֫>}nT^{!ąF=~/@FRgC\8 FOLԴzL2Pc]6{a]MGK{.,Ԝڲ凑Ls?pN?Ĝsl ]/27DZcXO~g&lKܽV%ౄ\똫w%u4?].p٧I-gfx%EefA"eEByp1lh; 5oӷnaRK"]&Qb4qmW*;^oO`vfv(_Lh'Gqh` +%=N:AWTI8+ǭk8^S5W8 61Iݵ10&.Sznt˪VprsI<3#i C N^p ?L,K!-]"12R֦qC?@ xkЀ謷WĤ:BY=Ogi;O)ی*D*W:T CL#Yⵁ Tpm2$$YquS%(oInb/}x]XSӑݤ)\>-֯#k?GA;~9pVe?䠴3/Aґoơ_X6gihTSMER]j|.  wcՙ4s{4RDٷ55qٯ{$VR#3w7X@k&.#g^H gUi RĐNX(f .NmN#W VZeLxBqi/ 5MJ蟪hxT"ɢ RX5h~O=$1ߤ:ءC;8 PH"M'_|:' tyE|?%$nE(ͭ'Y%iw ѹhƲ?=E qJ!-Eu3w>2`5?/'o<1ߌէkz:f{*RT5d}DܹaKMϴs ݅D*ϵ%p2 )vɽ[g,8xH7e8ݐ ^]tJ4IFRڝ=K[RJ @GLC<~hv ލSOWU, IPtB*&A<'('17Yv]d]Merc;^ x׊7;GK*챶9 &PSsoGOn,pٮt}=bh=W cVЎMQ,SH {8ܒ(.}%`{sF~ Ch9]:a>Kh쳔Q0߷aphXKD5tb .3~aVU4y4aL i]P]~qdC:.!BN=3PaÈo(P vt ]9OI1ڧOJ%p}ilҗx-URp>3,PjJq,Kxh2˩uN0"4DDyE԰ IF H9&:=2@8oTXRyGy==Gϒ_~%3n eRo4a 1aSo ?2ұls۷F q6P%4j֘b6y:GC ė/EV㗰xJ,s5F1eI=n{Q i2in]YLƳ{zrFrTۥPi3~Ӗ^o@Y/\<3Sk5U_)5Ƴ3g=rKnr!gg:9> P+Sh"NƹlB.Ŕjz #Yz͓+D[{3XE`-{KmdÈ_F3% 犆 pmLM0Iq^ӍWIJn85kX? ~TXMCp؃Gr2,I)Kb תEw;cn?M~,F2@;jL &O_4ֈӃ=j @"Ғ͗@JD^u,dvEA8}LM5}µ/8HUbVl[rєeiz_ļ$⥻4E6P& ~'DQp<~}nhIlsYg@_\ tc*^ZoޓHR|} ^3p $@ .CN 1K^q&}# g`Hڔ^Px__'}{>Oi}W'._ΐpξN1F kgn_!`x(tqjZ kÜ4x*1a{F6#`qjow+O<-bXшLn;Fn*au2ຐ`ho)Yb"UheFڣkz˰>꜄*l"9eÅ4D;hҨ xJ|ڃ%ۣ~7;cML|tFe=uA ,¾}F⃦ ZrdB߶ zP9 Kx5 Jw$Vox/,7؏RGwB=ÅBF?lmK^2M),Ř| `!teTvN[J G@lX@ѥhSM1?\)5\=@1Z7k' -B_!t~|d\QU5TTP9@ f{(-M^1$lqiIbGWlBR:XH 9Q\h.9Da06OP zX#N2RS-p_U;N\DxLBw( X`dw{UL WC #̖fݳ-:6)C6U4ğ>B^gF>YkyZӧ0#Υy]f)Hpܺ?0.^TڕPRz=f~Tc8N/_rNQ[^F RVA-g]Ցy1}j`x=enP׉Q^K$gG ɒN ߔoMb0a01Q w8|1ȺVO4 uvêϋfXHx "$K.=7f4Hҵՙ ̐}##ԉ]ƎW\ެ`ڤ攈B̕!Ē?o{̍' Rykͭ^*ԌM0&(A; ݻ]#QgH*܌Iu^L+뿓Y4rtAC'hL-%k2)Tfa)@ Ke-ۃTוR[)[= &H\*-0\?ƥjZHD}f/hYu2f~1\ O_5wZ.6l2*lq!i0: Dt]Z9c/ɏӡ ~9L8,3yun(z6aCF&;K+2/ư|J< fIgdYJR^PCW~veL?8[QRm^T񚍞^\hvoIfW{|?ʯbL\tS-ś /8<cR&h_ԞbKR)AgiPň F>œ{Tخ,}fMMaE3͜ NW&p:;'6Su+ ޗ?^bW3^m{͑GGa Gז/R-֩ICMaW gB'~<bR85 aɫyGY=}??) 7=Y^x8␼6wI=!WIvp:fO'bgQi#l [u*f,[J5IjP_~1M;[Wӆ3e"eF;q?k!7I蠁 c̄]:^ dᾏ*(d86p`gpaz~oQ }N|y.Og%,rA' =ekKDPЍU?|+ ?u۩ &4Zd~٣\qlE k xɱv-};OSo-LE\W)rieJB&c8. #S[h"Gx %ڟHrK2h&O+Qvk9^,f2;Rq>7>#izwrm}칷̅;(S_Ƃ(:@i5/rMN2BOto(MK ajnYP C9"q$l%4Ys`ru$Mj2Fࢧ*m]*aK?s#YTZ]]7Z5-|(@lgtܺd=;76w i(NE6]iђaNTVwOF熑qrC*缂&f5(F#<TVI6\ܒB(9\}+Aڡ=,6 YR-*ٝЃ+w Z2S/vzD(=R'Ԍ'ǫ2_ r?t {~Hm`e8RإW\V ^A~m01рEMo8$a0w [ӃO1MoZnG* ,'M9pd/]8rvEt>Va1VQZnќȷ$R=/w7THAZ}WE! hQGH}n4[@j(;#8YvcYJo x~^U6T^2"dꟊ* #=C|,pn۔(S2oNEàv&oI&7ny5{TTk/0FFnVB,]u +rAGeIv[7VT*EIIDT':fZ!['B E"q=I2ε!(G.-s;4xU#Y07M@N߲*˹eG9r:MBjcKa ~##C2oݝ/kOP ٸKKu6'&xE$M[[F/P(yG瓾h/[1XE|yOn[UXϯ P#o*%@>2c2ϯrkCnlH?bK:WvO^mMk^5ʲ6Idt6:rEXۂ 挿Od±V:RA[e"g|ܟr 2 {.[;{+*!>r$f-dV.1О"A)LYO#<f/ 9f3-#y.%&" kKϖv;~`h&`}|"wTPֳLVkZ*|-Pjhi߱X hKMlLX2,lft ۀP&c|WZ/Uf 'xgd)=01'm.LW$AH,5KY'cB\yR\sj۾wNb8lKHH$_#B2PEDq.+1Snx"L2_Oܑ6W}eoAtY@PUkmΫ(>\EG`':aQ`>JW&_n^ \EwFa )M @#:!oXrߤ^gy⋞v/^f |k!_rAvh?usvzFWZ\8M9.AV,KPt4|汶8<[z0ESgd)i۹Rd&](Q(FD7۸0? uNGZeM̝I>dyĩG uAæ}=&gL!0wK m1`[;è=u*.7v0-l\ju=˨%<&΃ղl՚áNՖ2n*W / bF2Ac q =ĬIp(;S9T& m)w&Xn#t^۝}3&<&eaC]ɽj2֠<2@ wdIAV䰆.vjms11ti$z>n 9<͵Y0=/e̐;2K'>!F;Ń!9W}l;XQt!tnDƝ^SRcbqKW̜=Pŗ.) /rp.uUPrGY]jJ% ;5E4йIȽ _'{&/izv$$bVࠣM[fߞ zYHY|UhVQ2M/;ׂf\jk:XWv|HZ8WƹB Kٽe!F~ ź|Pƅ2ُq3粃zސ^ċYf|1PRvI`8{w^?nh{tS49 2c@^` L]_V"I2'#@M:I:,ßM0_:A v)崉Y9._4V`qvsb1}@^Ž-81cvwEM6THqG&}my52NSn_IDLG'1ag(~SN@;29~û`\_jɧtXI -E̐iXs4š n~)!5ws@x0+D3Z s+x13zCQwTڪYUoڹo鉛K[r1ŧNbhqW7nllҮ?ܱFCٯpYNT$3{eX>Ӿ/3)x6Lӄ ? [CԝSBΈ*Yz1e.I^x4r.&ƀƎ}g Ũ+Q+AY8*ӏA!m 9_ ռAkXoϢKSG*t03iǞaN"|7`IE@3K-l'}-QiR0J\C jusyZp$Y$V.QDugMq-~(Ƭaη߉aMD(Z٪vY<_ͣHXh>CO&HdYۖ6 LPw_A@xz,:F%>O%-`f ԝ~[<“}. y?kcOr/sijpt,Y{ClgLj8hγtO {;:(䊅K! ]_"yG1FK\8e;Z~G;Q%x`57%20iQo@PA+,EnZ#7*Lh EYmP 캭gMZ9LC&д[H$[X%FxFطcV,|TLٍ`R\5 FBy#s/rMNYd }B:.߽@K"_E6|6d"d- sɰO4P XeY aBkiuC@b&Tfū]g$۷(|nr}Ԭ<0uG˄2մRVPjGyZSL:D>mbm IqG;y4Kw*~j]?̒4H{κ<grUm R={3>.tg#l֕ 52rp4Y7+}ojڈ0'faa[I>Yvon#\G%1/svͬ;N)bP5/lC.Q&tC|l|o, V4cm:5 {vrR&镎RK%Q,"iاZ bAXdd! 9D:uSG}GgbCRor߾GI"^O_ 1eNEQGԪ;}N.GC 4e 𖃅 @]= Y 15^L\*S~bJ)IJt),Rp;]zR"$%s.rbkuz(R|m QjKo1?VpcWO'fX L#6%7dQXiݬ+Ia}iv3\-'\GS{ ӕy)h[VևZ2"g}H#)Y:Oօk1Ic{".Pv[a Ykn*% VKBSܱ}&ʵGA]g?o:K|pi!x&N)6mϹ.;#z-%H36yfӸqVk55EqL+ikA -P](* ȷy(cao翌2Í&c5e/KT"VP1c]zDؕܺkuf^d襂&Etb k1U zvx~IEqH`V kI,}7FL%-̔iao@E7z.-P.񛠶J^뉺KUt4!]csBWFTGO,sLt\yPm_)аU>K5! wŊV#pj7l$Vre1IE$n3O_{kE]&#mii Ld_%Ig*#:q1AmüC4;yDI~j} z.Y(.4lNBvcdB7K8¦do7B~=bIz0> Don yf2;c E$?)\jkkFm: h$ [m MWZ@`gQ۪b˧[m,Z;",w!r%(0Ŷp3M4щWN~9kL."#ItWSHV9BȰN8Ad<|@ʍ'tZP3vٷVjuREGs7ĤĴ31/$4r#3R"[3S[Q|J@(ʘ Mr~\}ĄZv~YC?/>3r!1ЕԏCHΉ&r:R)۫hџseoR>x7 _O+]x˂p_"4wn4'])\DnY3TvV6eE/굜,M<=TfbQE)@ i!BL&S BKST1OCd?/di#jAfd2^,{^5P} ']4}zR4X-#HѴ{^7Xړb6Qp%Θ LT"<*"*c?3;LlϏ2CLA@PӶi:ɟ5q捂"FZg-@Cpl&m,dnx2&Q3wImw VUaeQz '$|u7E{дÏ@2u*7:dUQ钉 ͛ywgC"ȠsE8?zЭIR3LdgsS 1^ PxhCRƄ9݈OK_,f Vj1VcjTK+A]6,x(q)ci1en&a Y6GJV6rp6O f(ȃa@&'g84ad5Y}I\TYzRy5]"RȀ ?8D3{8t<\Rd(bE,[)w_ۡd[;#pQ@CQlj6cEn^ f2&3ŢÙ/ˏ /pb{0 ަӌ i/CIۦ}QAq<&.t;T=>u?u ocy|5+EQdWTB9O| ~3pcVflhT*qc F9?Ipv/%p9zsrBՖ$ô.2}M[+SȐ0 [r#:AHޯ} e zgR3^"3_gvn:/'M 9لnW=<.6pfBc _/AHE;Ĉט4Ѳ: Sj}7nAYmh' KWb**4ōltIT;j}6u~pź?׻i"_OgYސNvDOj.˶QPOZh$aP ZhyE\sGRKK4ml8=Ѽitؾgܸ w0,fF}3ҢJU}/mǥ8/!>DA$!#ۼѭ K>xedNRK)}V|Gt*4BOVM6j+Dx=&Ğ}fVQuѭm!ldCHO55Q7h-PLbݎ7)9,D0 U, )V85i&?Qzx/:%K &1lIq(P(q>Wt5ډtOdk瀙avI>jn+y>]zGVoȄdCAɠ1|hX쯤v/Kk^Cv֏ +EҚfK#6u ${ xs&@A!L @zZ'!KxQNS2p{ O[^B8&fyaU0l0[_͌[pt 3 g1`Yh둲k89 "ނHs.B"( G[|7T ?ڥwkz$y10$Wr+<2!hK A"{yĩI|xd~Խ^7 %`?hO_VP7-ᢩhݰG.@I}|v*$He|j7' φC"#.V넬IgqŘkt~3jv]#<}sU[D;1 ./PЭQR]!sh.=O`ɯ4?y5},_*!updj&|!"sL`S^KdE )"Ny exMl=V>dVH;qH0bʫ~#y?#4P:;boЋO5(jz6m_ VG`j;:ޭu0,hΗB4a uFBPhu[i砖yH+N푣ļWNjCws .g;F|E}.R0teB GΣJŀcְ1諙jAʵo%^[U)s ɫGD !F=ڞR8Szn"cI8e.V_`GP(S3p-T$Nǘ2rN "IX)}1~!l6TF>  06R@ÓKtiJ *E$/?ࡵ4BOѢo W8eƧ~lǞ- :Ŷ9T};#6"1+ߌWҷ>x 0ȽܿL9Z; ,"'IQO8A..j7gh'ҙ 5)U:xF.*hyj @Q3QvRE >gADc6D@)r}7≮|)M,?d"kBy1Uo+rJ1ªWƲIUδu>8Yx%òiy啄!NxF:{vBŸ2wr7%S[qZPU-F?$: ?V" 0TK K#uCddbfO耸V6>oxHHQ+<-Nkdp|.8==M¥h[Ə}u>(%xU"?>s"L23Yq'JiD(d>`GIuZjgbt;F?B(Ge yO(TD})R$/o``@W{2 S^k3[UO`Ut bRLtҿkv̠ ؓ R_ݤM7:MGmEh)z'Ѓ\cW&,3w,.K/k ()J.{7W7 V9$LOhG#6بcotR,nfp4ęv7p dnk)=H:V>#Ad>T7ڎbt N'e\O[5vn 8bAac\j'~pI<I6TO _Bv!ni =WP}jRnur1~yS}#nS ucḰ20]x {ˌ(6$`f F%͛}-'WQmqF~Dž՛*1W KrF3?XBY{pR&G9miU6ܯE`!ɖ uDu#xw0^W?J/LѷpcdtlZs1SIe ӃO8-.?, Pz4ȋ1Hx$ T xĞQ9İ{(!`봪9h831 \V'UzTr^-Cwj8ɂ7^uXCx`F\8"$l%_rӗtlȇ\ d$zlCyˎQ,wKQNufwU4sU a4C]NsE?.R[餜Ҋ)=M_@OH={T N_!kg`C ުӵ*resMՕ[&4f,!ɺllSe{à_Z(G”B6̻ЉOO AH%,ٯdnc>F\c]V0yEmwwaCre%kŨpv9{BNlH# DTʧB cj<Z#~`Q*}gwZ`x~K_˫g@Й0 qeE;Ym}{QcףWDS;X f|cA1ۙQ735K Q-%ohi>褤OdQ{ Ɩuvy@92Ef·m#߳bőp*J@.`,' wsCƖk(,JjCr{5KԞFkFtf_km&e=:M`ݾCK od]~QqՎy)C[͐rݢxwtOУ%2WV:IV!Q.)Qeyz 3r ; TKr(LA-S}{S/*Xn*83}^au2odmίonȤy59} 3e6(@]o+T,h_i𘍥便h<|matB6о2$Һ5h 폗i)L{uȦmΛh|rEga1Ntk+X+i/ w]{Tjno2TZL8o4A`\H ^>vHVQK:;&dN gBE:Džvˮ=fRB&'_250|ef\hئi7l@V dD!XPPnWwQW=ycE,i $YIFEժl 壱|ΡLk _DBO1v̈ˤ#篘@UK`8~J@JP R(hs?/b꽀R$YhYQ0]hk,UK<\Vm I_E,!3o#"Ń=ws2dw)P<{ )hxfe!0425]<[Aw&{Ш.:qI=w1iLH 耦7f?9t햖+fcD!WH(r޵`ubıFd/1Ins N/ @a-H[  wm=oIa&!5̩DE6Ih1[yI Ga+*k-HhW`P{l3c|~]t1) |p01qq^Xt2萿9P\w"6dǿAruih64OWg6"O+ oL2|{2dQks"(Y)~ VBMk1CС K!p mIj|kU+w q ȑycA O܆%d2|L\Ӛr쒁{w`Td',+j0**N4oyM4sEgя%JWb5k8:%D@أLhr܃͉%aм̿;^ɠShs3uRSt4 S7Tv늎o0xTޥ ˈ:; ՂX4{7j9AmT`teZ:mӷJc ~ }׀d՗lҵI&-g)Q BoaQS%[ȥW՞o*$(eK7Wa~悫ԯ@PW \#5=5h},#!R 0½7"-XW4))VupO.OFW'xiǧyi= SQ i4(T~aM"z߉`,^śv:@råڵz/C;g0ʁ  ~T@=>nESXnUyJ-kgE\k3YJf$;*BE-@.c7JK|)BaH_0 XL՛,Y1+R HO@X(DnfQʡF7U }1[3NYv|ŧlu>J >zB95<$}[o|eLu!O^5ҵzhͮLԖ/C<9dyv/wC^(t!rqؤ(UYbg*^:Hf>vv2-mTI2΅C{Mʛ^;$э-b#"( :]81RFImQ UI$)<]K4Ռ`n fxkKgYW #wX+c uȄ@=~/0.D6VkX91Zo4xBJcG?~F}Z"MC*,TL`D~'mfiνr-tN(h gRvp[_Hu6s8nHw~ԓbiX1`?¢TV ƎIh^iޤ./St(#blֺ@t

EQ"<-5wZIOp aiO.;3t_#2QsSi 3Ҹ@ԟ@ P $PڬU@yNɲSC'v͌-U ٰ 7'f7[;F8֤[HǍ.fA !RAۄոzTw`B|9i7ZJk)&\j-V'`[آgZeS_=v= ].oQ&Q[QyB#A[+We3p8 OjŮW?X CdO@o=qn"Qb5sk#U@WvC,A3ٽ0hW A(ˮ 9~kk2CZ ./)Pmgd=.HhӾxܶ#jQj,0rID":QhYDР7plo#ͿD!Ї en(MV'< [NCB> Q՝J!̃Ʒ+@ఒҮ%3b? e VV~tf@ r-CO6=3Q1L-Bp/h]vD z`H.N H8G"5 Mܘ}[ѢP"gq4\hfB<7W j'Fu_S ubp AVObF C7OvͮۤۤlWK2o9dBj԰55.r <_G6RjE!>GߏXTҡ~ےɻ>;yaZ' m)O |W)1D[ebkV%];o Wfq}v}a:Gbq^u/I.˅jFI5Z~(sYKԙDߋ?$xpofSC'W wpUc Y 'gW$[=7On[|7-{yO[OO=KFq'gb ԨB)f9;OYIXzrV)E㨫?^T k3(!Fp1^XȜ@fAx"\oPk ilMmx;~r(H _;P 1bJ|ĐohnR 0^]mHg;mdT&'t5O/-Q [4$5#$ps)AN*Z@KԴkȐh)R\bs̜dDyV* Oc/뎪{KPoHf{T0 ÿXr6~q{-cy]<5"`sX:˟ސˎ8d@H HS-saA "p2"8)6;|3lVeÿyC)E kB1g6Aԙ_CTZvMUP}7 /JGf!j)cq̡cH4y!_$[ 5xNbOsm ?θJ,bnc0n&KLEWh κzf05Tͦ0lk['Rv&'iшR`ɰjx승^HSՖ@j~t)1|Tu_ϟq)|( \;%Ngϕo2>lP_R̎dpFn!z+wf^qmXw8 @}4/&~M/VɡCGH6\*9cnQh98QG0v[VWXÉ4!v pBJ*HOLٴnZO/DmBǍe!;/DAFCWEDk?[È>taѼ1QD)R\zd=8a Ч*ӐHmLpOȈGYRԁ?/TA 82q31\+GtBboѥ (She gts?wd\fǍƖ}=TNtWIiKp~%aNeq0} Y\nABCM;)"UJmf[ =N67YL aܥ-Kex)QI8N'Љ$Ab Dp/wIww^ F뵨yI% v'ZH(_Ԩ׽W!"'appA;rp͒V_o=r7q.5OPqbVJ7pHy 1a|w˼ d.4 'a~(6 b|:eHͱ!&1-xTyע6~Bǘrm\# 1+9c{ Ó]/oqj}.UXL*t!K5a !_Ly\ew7-QJ [ym>h$iU7stu{&a _IUu1mƛ(v 1`*4DJ]br; M6ye6u~s mQhiet8>`myW\w ";%{,Kǘ􅯏TV"1Ձ'pWK+'ؼ冬#Sq~_ӇX`~rHdXkB;m7|t*Uo Ez$u `InS=}Wd5&۬?D  t9Փ3iԍPi5"#S'MFV;Sgn oQ*۶6, XL8*0Qy&kp1w5Q%y"#߅N@$CkIn|Pkc}zV9FHPYWi{-M6!Q]o4 Hҥ\x`=#rvlHՆ!uދvr5Hٛgb?q WMDv|d]#^=g8I0S; EMIDR6׀_Mr!4Pe796]aҮ[ FӚ{-@FMC!N{'C7g?ZS} g˷F­A\r>t9ALjOr,? KքAbg] -J}f]ΑOSr*^?"S5S@LBOI84_%kƴԡN!(M\zD6i[v|Do81ڱ*r3Ӌ1Վ$ŀ =4Sm5:W';(l[ffz%~k> %CKL8ވ |wOA:XO]c "7 Ǹ:m5E8[I;t:5#;rmHzg'ϼ>s RɨL 7eS# M0Xք(#^k7;^K9> ?0m$ ۉ:oSzp0aB1㩹"dyI`mnBt}*0yh_:6;^45d@WCA ~Nb;jTv-fM^9)Y1?UO7rLײp%e?*K8װ<0y XAFFDL0T r :(݉ȎBk.͌Pb @iUQ>!й }~suMƄY%;zAiJSbt4%w xku7q4:b2#6Z;U:}#$}aw:!ժ-\JiiByB0a8źP lY'Ǟ槟BcݢܹٝJ;;j P7#)-3t =̨ϮK!(M)P}Z|xmdbvx!-P nszq 4PvHͣ8<DND5eMuh /Ki|'h3ѥѸM5Yj/3,iV"eIV; jTNe!L+GT3pÁY(QџzM;Y El0aB͌>65(U $,zVJ&n0ĿN̻/T/( MB-Ax.wdW)xS|*6*g⥪i-qSc_Or۩cl|"/\K)͸5q+2|x^faϳ|$t5ЊI)_:a5R75]3C!ķ9dJJky}W6R[ņjStA`݋{FAI#_!b?0>(WHO-ф2twQV8F21k+_ZCS+sr[ ^6t؟ŌL7*ؽxSt >:Zg5A2&oAB&81s'~@!$aj\nsW}soTr R28iĥ 2KvP DfhpZr=,`LnT3,E2$IJrxyv̻$LyxyK|pJsH >]X. lKJЍT 81U1a$z+d iSg/jayFXov`^+NsN}mh;8O>\["DߴKz6>C1whأ+6 HYQK?;H9z&NPU|=gyt靱n.o܏2%&ϋ<$#l7FuֈeqmA8eG{ C癛c6,aVS1^.&pLEcS--_"8I^LRo-]1K_ޜQ 3}gw٧S9Q{AǓq|17:YԾ3(6^^^ М[ݱ0S=bN.'iul~Hkv1tcf|gb:?V\u2c_=^[k{^t}z$kSF;SC%Fmg*\:Kx6ȸ.#1ĭ_{K?)]qoK뫃0۱z.eu~,%9_%XgkSē='24f COVvAW(='K(DKhGP|Rcv= &&۴ZlkRr@Tc7$̍<4ͮ 텥+#c}7Âg Vnޭ0aeqy=Sr9"nb8+|Es$9HU%G$=n*O+iT5.ށ JS6mx׶3sb!>y/)'M8s {{vogkhL$$a 8 8[r5dKE u1f-& Y(ZЯGm_Z|,ygk-J:tt傮}~}˦-& TDK&H㗧ǭcUF@\`"Ӵ[#9AӜtLjјm(54z4MJ"zY'1?"yԃ3PC2\@0 >gϬs'btϯvOUoUEJmo- KV~/ϴ^,C,&-j_3oW7n;"6c 0r_1vuJWKnz r zsCLt羓Q0 D!Z \6sGk+]^lL SI-E$b>:cDE",@ah pE' <9*):qVfoAҎBc#b5+12yJuNlwxD)P}^}}|*`o6UOo,D?G) 8 `Љi6 !K\/Q!^mòl% &";hLߪL+6UQ؏ .¤'xCBjWN ZGƕo?#@Jhс94 0es.e2W|.`Fzl^E0.딈K̏Eb @.yQˏ[R֓+Cxp :4965 2/,}0m:yxz?2R@]h0hy Cٔ6ؙ,Cu6o}d)SL)X^{H$k'+5vDNsPWB{{`ugD8KQ85'j&ᬬIX.+XO-9 Ϫ1% w!PnM(VQA~X/)Mn52l5֎ݡ ;_S]ZGex2v(;O^^ګhWS$r!նH*@Il!{)"S*]w#Ppq#0{ Iz $ {Q6@xZ],7EtJ,uqtA1y*&Y* 0C93{>RXt}ХGlnHq5c-(3i Mw/>|O]yVҦ#ZjvQ~0^5?r'x^o"=!hemzzo(0rIgٮF 2'"UEYdD?` '6t*0w9j.Jw`o ̠5Ą5B Z.vTDN6R3~7Ԕ1 D.ӌ&U]@&Ur adOCXPL 4Yy䡙<[߼n /+M~LWy}!c} tYb,rhr'^9.ck# з5Y?aݵT~A{"?JѫG#ml\Tՙ`mJB YPf083p<8yL%/ ư ZTzAѷ . |ҰCfCl Bq!Ȓιd#RifGk=@-bT&<_cîTï,4 hq >?t#-ds϶ٲ2j3fѝ`׊̦sn^:JbV&-9jڐoq l8WwHZUٕKl$cI>dw uBtOs@ H& Pa`FgcΖ5t#c5&DJH4}<\"22vo~4nbJ(㈩_6~YXY2º&PkSF.N-z|sT%Kݝhg|; eu+\9u_·:ZhkӻC 0쎺y ļ?$V/ ]ʆi2~ +p(U[.Z GM.g\Ds/kPtTƶd|Eg!0=9C'X{7JS;&&Pq37H" -<^=_ ʷڕU^;} F#Hg7kf键cyh  y߂q0VJڂ(w6:yhƥ>d+MTbɎDsc&y@Hvә"Y\Z?1G%𲘔^M'WVE9Kg$d}>h=Ai_^[ƫXlеqgxX/`=MpdUrhDh(QЈB@Ac3ϒ\󛈨{]m9ֻV!QS'nIFH>(kH᳖` :#Z_5,,,ŨeuNcWt%/LB_UNX}$Έ\.l9ne'dM._MIQTOU\w}h3b0ZEnIkS 7'y_k(T\to]"p^neG4JP1~ ؎R-+W#$oT;l:zT^KQCsdSNQHϫ=<^aRQGisֳ{XD Bm|. ] gU_=˫ҝ /GhЋu+e؄ᳪ0!O|@4zjxfe/G2"2DjП4ޫ8Po5lĬe+!_{3MY;&dҚ\x/XKLT@^%ev'뷬L}˺tSYQhd"lDX4๭f*DI@7Hը8гgvڷۚ\3͆f5K]ncpfH2lyt8;˽DzEl~7ִaWڬjP 't Jv1vSf6~ .s.6@McINI*biH QFWL'{J!xyFt 1RYzj\No}Xr&sH>)]dvēl*F 0FbFT\鳨HdC ZLûM`?l`q fzh~~u]ݮ8/PXΚ .ovhl0 "Ncy8țS[.6'1u"+q9M-<AS!+JXZ?S[Ttۛ;5KќI6ե,7'ndIJ@(\rd$^u}!m-ÙOIEdIpJG } p~rOꎐՌ3+yCi K)@CTEY}2\4/'I8$P^-kRzYe7rU̍6ɞ)yb6WvAx5DkN̛RgR?+cҧIpoˍUd=? ΖD1"FŖi(0,,EBFbE#ӥQEkp'3 GRH|R K+E08`tޑJ/ě;=:Z |7bXꪆ evF:ᛥn_\sU6Z-i$ݛ6jfocvŶD˯c_;?'l]ڂ_G*|7'esQmov "G:)#wt6xX[krӰtRYFZxI+ oFb P0w!L 6+=,{#TitȰ R QvZm|lϡn4 E__6zE$U)Z ٧qbt) nXn7z r<!L&;Rlb-%.te3,51[h1@zu3FS`h`Mt\~vm_Ngw< #! 6~Mr^jLnhN)ٍ#<|(u A(>3۲m9G"OSͶ۪r[,6T Q'Ob!@\`%A%q ?;HUUoDŽc4 *;B-_$\)akKwD^d">DݬEzQ"yIH{3b Ń#h p3Rp2tQ疔l;AY"RH7oG݂ u8ETN)Ϲwor__E{)od9'|_&-ќE3L{CRD].s'/3Ax{izaf#adw2_% _S׺HBAy&ˣ=Hx h99#}>QŒN梲7pm$|dHO*^tE< v~r֤`tA lP pSn[ hE16˖p1۩2uM_?:ڙZfS,Z k *Ь6<Cul϶D$6xGAfwy6~DaEBksOZ^d2T2ɛg "Mg) _d{ f,T wskAA"g5KJ@ zFX`՟c/(`Gý&rvo}N7pИPw3r x 49ΒE]cQU7TXoo[ _M( :@m3PF1.b*&l Rx+Ǭ q? i£LEh_b5hccPRT$=W/#ݲ?;:v$+^'NbN)jocCiϹa{TBI_'9IَlA_@ Ƨ`(&qYSJ~Y͠װmǴ6Xl(NKn'vhAZAx>ZO8)G@qHp++R eN>g<̽!ɟTۡ fR^P]Ft 5زʑxPı/`_`) YoW:no-뉆p0o-ޑ8y?o{'zALím y= ǁ&u! V_r,LZO[JBﱡY*m](TA@ۼ0h $+˽ c3,y6=jNY8;F:U`4>\.!m3pR1#j)w䰾u2Lg0m9 ֲ&mnTa^?vVB<;3@5I~ )]HQ؜B }K6_F~}3=V[3T=秃~~Gш'e̽$ 4d,=W'zqN)e>]Mi5>"7 ;{AXy>obc8F.n˜IZOJ4Q;#taJLg?qNvlny (PLR FKzP3?VF䍩)1yv%q# XWP=Nſ}5n` p)sHE#vۆw8w/Pi~'vҙx!([sflscKz ^._d;Hu<@Om" #{.>Ƚf顤 UExu( \ț~ҥY'oWV(5aY9%cѴ~K `!Rh*6Gݗ9Sx@=o}|!, jt?zqnlR(KWC{9oYcqqC^a$Yy֏&b VG<<ɏ#_Vsj c mp0* 9\(όj~' Ck*^hhmd݂YA '$QœoZOX:ERbP{Jfm)9bĂe:S>óF[|2mr B(7i ,s:NnE2).gCƋW hk:0^IYHpdHFTl8zY,iTĹ$>|QW=̚Dk? K \*?.@ RY;-G;h0vZ1HK {_Y'F/ u1jʃQ?ezZiDHG?7i8 mje\eY0*;ܤz:'tuL>t'JY ͑qlyb,kS؈muc"qpx JZ$q` sNn`GDUIh3Y nG)0td=/f!&Vz`HO:nhP$x#c^No#`4[01VNz;Ϙy&$YiY\gDUq yI2]پJKHTMBgO=1:@ 5+/V'dd ' .\?gADWo}iS{**j1%=V:EKg6^_4р1 k^zE;TN^+mp( 0t-; jAY.~1XoQxP4+ᑲvO~-twnzNyD{=#l:,2b?ePFAHM<|clLNj!Xu|*|ƘTpƍg%eX+8!j"Ƥ e?lP5/}6aHѐb.wcnO $la}"<`elrg&cB#P+gi2wtqj>ާ2Rl:x* eg,vt%#qHXI2r%;$MmRItƇ+T'J( VxK&SsLXv$Pd\H9 _}+nb X%X].e":A٨h֌"l!Q`9Mn@<|8 YNGvZ)rIްU_ `9`bߓh)։b-5pʖpgP4J R^8s{#t9mOKL_HFBv xiF.(#OᏁK$\ƳSt|`iEO LhZ};eqU*,&i$6Hzߙ^ddY#IU2_^U!n|5&a iڍ'<=ѫ^O޵BEwN5'3_wqpD96>'5'i( c;^ NCgs8^]ւ!J]q.Bo_7+Is\ *W?~QT9ze NH+[]Flh#%jQ|I-bi7R Ia1%F%IMe ˛JnnjK^PBBߺA)z?l_-jCX*چ"W q%z 3-R*6o\5V)ŠU7NIy5:"M -0A}ܰk79t$R9%O:9}jVP[@OZOEDkӫc;% KA:#Dƚ6&k!$T%P̕/"a Ks+MǯJ{):7u,d{t;}~ +vc||d&±@inbB-Jw?PJY x4 fnGr- ޾AYn9QTdwn`R|~LlG0Ru{15#+}G YYm"l.V;j6\gHg~Zc,,:[\Ƃ `.;FaS2ȥ Z@a0G~mQȥA8Y-Wj%XF _yQt3ѹ˷ԣ:bzʁsGagRvI٣zXn9$1:vepMj'E<r=xD܄nx΀YR>LV})WS80jB +KLrJ3+(?dZ&}n@11F\qGAiz=U M%F_wBtL !N*\:R_88 ~fKJ發 ;T {X-6oi?[فDa78΍gDU*WJ%EMxC"Uzmӟ/_Znf}pZΉFBu+{74r?a`As3@tPT$*aϴSLH+`"m[Py`yQ?{4XAe]G~LW'  fG3}Sa&l7ma b%p!d xyjÓv p|9(QѨD5-\fP42d*N"I[r W)Ę2%i>~|Yra]**xMugtgEcxik4 M.=rTgDl T)OSTCZVKc;tum(kD/Tz!?RAg-}aJy$Lr%J@/B:&@_~eW^y9?5oث:t7á#Kwg +{szXmI3im9%j3=e{dTQgA _ThM-l;2[2mC!`aW۽O(TH)K.e%H$񷤊#ޟ?xw!otw l׬ǕcO)AlU&ɤZ§Cx *?@Kl,;#079hxV8z@>MV*24\0yvQ(>(B@h5I/n1f]GԈj+2*3y9Opy0;bra{8&Lp-2 r2Wآ H0UF'­QI7׍'Ȁ(9%~lg}Cp4} SaQ> c)j}׆d?$b/Z#/JpzKo~ȭ7Zx Q^s2)tCCHbI,G1ruԲXT>UYOcXavImM9Q}e1`x^G[vB^#W:9 n=/<3=)>$3[::[ź~S*iiQ(m8zKJB5d0~k!5sQHUnv?rqN }TKK^ozl$4>c=v(ꁦ"%CgBH蟪sD}76:3ǘ1!f_GRW:*6NO"Rno2p8G˲y2kR,d@ux4J+d%]vy;:aRms>%r,Ȃ$9 ^J 鍇Rgܙ^?2?Kri-7ΠOhRp 9:?4苷G (;Hn]|VVFҐZo[oZ s\a07Ncyi1,'^/ߊ6n9^Hک#2\C9gPKPg{6{6B1}$<`,8OԦ[CG#4 Dlo@6!1}oh_W@e\zZ; *Ȱ̷ ϭyܽ' 5|@%8O\]>(?͟LbVVɌk<$et/9FDWni_zW] [*9!o1Ki,aC ]i |T i0a"uJ42 <;w>Ikif_‡T3Vudz8a?I(AB9P9;l$t g}Sm3ŰskfdAbޭyZWrM{,ctSqub Mj}ʮzp|HKܜބ܅fӁ6xW΁& ثZ rOWnMFib45k%˦3Tqyx&0и) Ka$MB+)3c=aشyx/ 'n.ۀy3'wokKbP/0E0 ]D{}4,g1]t7JAzft{`CK( Og '2Z+v#>PmZa{ʦ;'ŚŊ>"q2GHf}GEWlBFehHo>H%}ǺFOTLĴ3 ` B7s]mE Z;@%xh*bȜKm%ʂ~ ##CMG6{S$3DDhb z)Idgy@:c"Hrm, t?XzZF_A-SԀܼ q0Vyeàz~(E!&b$@!9b7eΉqyPwwx_*K>vuMcR8kءs\jj{`cl> :F%s06n2*_Щh+m,ήy~8=U EZk7'N,| ?^hM(1󟻁6< NK.ߧ_MkTߦJErq/:UժQ6ԉɰg? ^||FusOF}Dg飶3-MY|N}h^T|rkw[**uoy~93ZU8H,JY(E4&܏yJ[vo6_E!eٕo]د2M.o##gzUhd$ ba!>j+/DNJ<{m%Ć?$L-$0$fDZNY39`{V KrCuC}^ܣ7hZPqڶEWEvbg=K` p7D5(Z50!KF&Kar"qH+IԥvMS8/Sؕx|  czsYx3 l&ed1Ε(Fˊ-/ 8wl-bE,O:]K4sogȯ,F&DoT?-g=JV)uV'>q~M_cIgz͝t^X:#Od,Kj`PW$eW? F} qlE>kQo@oVe 6ėTT 8gO'?K]2TQV+~hH`6Jtn< KRDLv9} |G)4/X+ !ʭDoZ"?zA`ںrPE'%?6 9 ]P%c[Uu׃WyqhxE,*ͼg;(*'V;b͠{y+nJ ܷBb(xo़xQ^0'%O7C[-aT;K P]oA$pBlCMpOe[c)5qH?j7Ϛo~ܲ2!GhXj,v1P19gv6@"{Թɯ]9NDjv17"ez4\[Pq@ie]z$x붏m`@XՅdfؕvEuqJ6T vqb m\)mFu6g_j,..pj5273"UMÝ 2ц08=N, ZfZ\wizz؏3akHgWy{ؕEIl ँ6cQņE?5_NSyKo8ۥWیCf( f.8Dگ,^5׮tMbܯ2Da_,VժAZ7`t?ሯuI}*̤ebmfFY\!D]"l4xڅxUPo`yj`)'MLa<=DDŽmʬMM%+[~h9]TFbC8p.?n˨!8/{ og<;>*^9͎g_95ab(k82Ƃ[QUGhOO1~uvn=1)vʌІA!U?R7:$瓫.0_}D;Jk4)k)0`|co9fL?k =jTcԷf@i%d~hTQ#"]302F ^u67N[66z2BOs*}G32 ɠ ؔ ^Oi|e 9W^ 1:K[ ?X{fӅˆ0 0j$9VˬgZl?7hRB7IWQ'[G"a }M|IMѳ"T hJRe䨃KcDKΓ%b=>IF8 :Ȋ> NVmuY c/ X0{8%RxO hڃ=IS֍s2ŬN1/,}?xD!;:"e.4;j/^*K>uo@ZӖ>Sy)F ڪo(ű@_UGLe2zUJQt7Al*%4eKۤ9n?9wQ՗$t$k(Re,@QAOH$bf|Tػo;?IcPaSE<xR9mۍ.m5hA2SΘYf*U.J^$;LaKC4H6Bl}]>6]<sÒ-z|Mpg#_Ռ4v/ xB9D ,BaQRXDۈ?ԢwgC"Lc,3"ۆWp%xyx7 I3\wŒ{{Yt~T;}IqjBּS*4M6`Y-^ѻp9>Ft$Ԋ/K}Μ(rh]>1^*8(C#J4%|9BF%wf9c<!j)*ZHubm%iZO }Sh@6 0og㎗%+!NԣȐtxBLGBtw* 'tE^Lpe]:Y.k{ឥN*(Ig|u|*}o0W(A7B"y-])Da.O ԰U3_u/%OMdwc2&r$rN^!].nTC{٘VM6'nZCJ#G-rk/lʪrݐ/荟³\O{Դl mugCpN88c}kO bۈߝ8#@˭jl;y aT[=,nw~% Z׃Qdf}fzIK;Ols,Ea{JdN՛52 xWVz}9 oPsW  D|o!aV $w#T.cŗ` 5kr-C-uUls bP_/w899Îꇉ9:$J$hn#).f ]vGKsa0i댼xOawʩrtr[(6ŝ4ɜt3g=@HxBX3t|Qݩt)Yp Ҩ87l}ݻmKf4`)%o2냃xl9,9_ :֪|v颕pL%@ 3qu*Q\ZP3vwKxL5%AY^A\0nC?@mL A絹{eZQ눿w/QihNQ:&m>W}c@.Nن.4efD lE CD\dOx_7D(@aCbCR=+)LVhP!I=ˬV]eiYW3)Klgd {w@'*5j=8wuH*Wjʾ}3O;bȠWu6`_lx% 3٢њ' 49f?RM2{N "db3֦3Nu+?ƾ_,4x /n8{#HY5=a5$^e{nOJRlN,]:2ìj"02B*&f Q| =<͐)hck eSW ^V7˞b:{3RX8 = @We>iB2d۱BǞzN+[?܀Yv`l4۪e ۛ[I:{I} f8+ZkdP!M~˓P,j~2G:$ؚ%$ztfnR/%/RH-Q' mJ|sX&__){HnGo܍mX}-\;3VzTJ !1\@pwkQ!{1:ݫV:ԕ#p_[y.a|$cgk"UztQB;ִ .0TɍJri;Ҋ'b<~B F"'pOneEf | Gy;l`5Ӕ W[ בCb" V.qaޚU= pd+7tFR/pJCO\gHDuqV ~\A<'^>p?`ڵC5WA8u/x>#W2}MHYm ]e=.+* N*> 18XEYq'P K\3 Ǣ`A'sϠ4ܯ>,P?$b$ֹOa{ŽIN\<99U>SnۀbJ+-}VQI9 >ҏ(s:0,ղR .=~x_uJGj4˽7l$"-zH(wAmh$A{'A}K.E5(aO$ю1NdePC dt.nY[Ap,U_76`RW8<~ZƩF\t9ظK)J=Am<{R{q%L`zh5/" (1բC):Զ&QJ"߰&LڋOK8A+ŁYQ.kA/d&`m2~CGb{b[R).j>-t+Q:}a馕' au]OI霸_Z~̰@9$PD[g~mt_`r40z];/jpݪ0z:Ń+ÎJwY WHyY[oa!f6 JeU@RR[ e*5&VTh-'Z`JY(z.#c#ϕՏn4m nŤT ǵK!P>U}fyC^Q*@6XYIf_j̮_c3VG3py.|qQ"l$zuQL(J1_;pvy8&F8k#<5"=u[G6^f/oG6 KrQʚOg6򞌜; uTЁ?)Xp6A.9^v v&S~>^V@wq^e,`>xދ [)bŖslډ nO䱙LՅAW^!flвF%VYY 8(>!^|@zV4.<"̢$M~Ygӌ|ȎQ$ ΙIg^,SG=f?hu*Ld }7^֞a8͛빲l#.kvs |2H=hHaȵBgkï!WX[.Oџvž{  @l:S=iB{b7Œ݌ o#Gñޮ{ g[1~2!cS.-ѩ7ؿ-`oIw! VI4S)֏Pi s<=c(H^őpYM3i6:J{| Iu4&e6' BƚQaF3@ 6]$u A*SKR'y_oט|敉EׄRP@71Νb%:)`CBT?$FxjU~THp/!@wِk.?2J t.aA?EL2ޛ؃2B/7sl6:uZ\4,˂E?3#R[*IywxzhsSM܂Iwn3vC&YPMX`F< 4("# l =$OiFUn^*[E\*9~j)С9GVo_./̨o~b?qg퀘ljTkkl%ڌ?!=HK @p$ '纟Ɨ*i)NT{'#h-4ڑz@Hy0_ܽ@Q?5smSHU@,p>D|z!12÷K"ǻr;<*6f݆n /75h_ }JʭNnk,j? (/S^L&ElݬA0rjhP5\}3N~Vy&2(m|枇|l'>gurQR(?ԍ7\ID^c-ux X#vn BIq}pzJ.SB?pq՟{K i ߐ8^G{EGhw2㓙ߟ z`ˍڞY 4Ԫ6ZQdtCDgJ35a^6a6h8@|r)oo^F錪_Vx 73{r\˝lvD *L&W{Uw)0k u?ؘ$r-u 'h%:K[o$}g5myIKgA`_Țh8 = D 쟛zznRo?]teJs n5:/z }`օz+ C, Wk1FD|{:Pq@J2Č5հB%UV {&VOܙN*"C=P܃Tk7&CzW&HiiXh6e-A5ԨZШ WRk2%\=nlE `?1zcۋ zp;4dJ=Ε^w}"ݖk' aVI9Ž:gn.l.CSؚ3:8u'W(֎$M+8Opqy2jbqN~J iK-w,7'<S+<olx ɥ|>rhǦ|{i+q9MsM5Lo@BFuX+V?RޛMJz~lC2^}@C x/mj\Bۇ9-$7S7#=pݤ WtcK8:gU>32b$$?7e} GQd pO~HŽ طk'P6qA7X=!"R֝5kb/ݿZ$VFέ* ɦԪyb(\K+zDרO#+p``g_VFܲցZ Q,6(2j7II.5']m1AG\ø=.r%hNe_9;Sdgu{M=A7 N-z­0&N*9_Okav RdVڏ6o=ls6Gf@EhŇOH=W;aLTx 9Vﳦ*/Ծd-S{ &'K b*:X61yQ$c7rwR2L(Ķ! څFw&.գ zq0mxC=ZAu^]B:oey3F<2MTރAx1w0ϚBv5-nO>$Q;>A-Bmë6qd NAS2}^Q1S.HD]2hQDas\o˔{:'>:t=leכJvgzˆO. xrL=heq[%/q l_*!RY[4(uuy-./,<5iMñTVN'Uu-HVnz$v>8{K, "'y-FOݼC4:W:֥-3 tqF`mZxUR+OTfYz-VvAL>O-E2bb+nՒEiZ"h!HmsbbwS4ڻQu$ hx[bZB%hF=NLjC,N1ql\xF-jVx⼵KG!p95y$¯jMVK,鸐 \ܳ=8Jcݴ.x.GiWOQ% &+6aBlT0sQjkL iADGvuA '&f>RsiЮ=!/cf] Oonix|cE$DND^LX8 SS.L' .@O_u+&ݮu`\[wE9v,QPzѠ?\^`9 zfjRETZ~Æu!VDθZ{x$}9Ke F bP. uQ{2rvr5L経ٺ$7: v6ns>R ZE2Tۆ'`@YQWxR Q5oZLDyyG8lҾ!g-sx6e9m[Aة ]վ F٫ܺ313ϛibN ǕN2}gkCh3S P~_?J|!ATyXxȄJOem*P y; B7t$]=&k*;Pzn*&7+k_D8իT 3#b30$-wSo=vzY}M_>jt"Iu?0+{m" lw >?:ˑpYcN)%=/w3FI͍:ŇIVt)6՛4SEefWx:/]QՋ\س xPK5Q2{L:n7I S4D|X%x7-ލk\Dӹ9y9Hs^'AZtώԌ!" ZWlZmƠ?6HkU$8 7 &Ny-젒.QIfn(N}ذ#sHfMw64ICB^N]%0aNJ{$O چ^({ xB z'0}΀kdzml!$ue=ubuQb˿h4\J;?i[' {?*-=0d_W^ݬDY[@0W$͘ E< {S̬lnBjgO\6k2U((L<`A9Έj.- (]_q*epny) t" ֦ NNQ"W>^M#~')6tc"IM'#v_ }Ytz ΟɄ' ~j"=P'^CC&rgf\yӑy"+un H[?.Yg7Z <D{$ອ0il 0mF`mMEtF4DܯR4BN#.~ޭ{!I2Cb'}1%D/O*lḴf@v0M]ӖJts4 |q),}gM M7 9dGk E|߃`' rJ+I؆uH.s3doGzJsl#vdJ+ P8T F1+瞾KD(̯Q:F!]Yvmg$3OAoR"XRٽ 77/D íۥ'֧׋{爍"$oC[6{rz6FMXLP5!@(6J;:}t[}oMs!OGmos fEJ9Ԗ9Ѷ([^[ |%C[9~xmACqrE7~U\59eM1i,T: ΕA`Ytޫ{gmBpZ-fy'<˳KUw nsp WW)=BlNZ{i=f:'g.X&ߦ>NT3^Д+uY[g*SD%8YX] 芑WduFiC}ˢk"2{0Bj"[17`3YJ媦C%N*`%I^/}[YpXfBx /{řۘ~EpûKH2Z:^T&;Ur~1SF Ot$0+ӭw?ܣ?6͛RY99"ơW[B[Y@aHDL 1EBL(U,)i̟zIg̲WМ~hhw=s 8>hֹw aX+!R G4tD&~RָW.@Jq=B N]_N%,&qu6{al9q$G-L,bjPn*Mwj@̏"5d?WaV\MFM;?k&Ճe6kBgWeAGo{JHU5KmɻD-fgl9V߬< +b{V`3s wIΪ?Bs[`K]؀@'mJ͎ $Ҽe J6[T4bnձ V( TLvi6ڦ;լi4 ڷQKfmȸ[s-rhDAErߘ3"{ZA|sً|NcHwZ  # `aX,e¡1P{Ec $s(6&,Tg+8~AJ t$I RT/CM{xlOo÷e5E԰K陏 > +!k 6ICC։XvXEi`BJ #YXT%:5~Xtj31|mVKcc#_2)_DX^CEd7]̚3m)U)iYKF=gXfn!!7+xx@vD>B]algjS)le?8Ӥ gz94?N$풘dirpQfRjO cw>+oG3V{s׍K`<;W)D)|Nk`\wu'R-7iV5mD$Bma۶HotUN\ZyCS@(×hΈ*VNs>1?i[x,ڙ-@@%EY֮nCٰq58T!Zՠ'JTUKw[2Ų(;t=#E1Pٚ;i>Jڢ;MR5uMV$6qqp@ ,ӒsPNm@g͂۾|Ńt[Ҏ.C$S=&yhsx!)7q:4"(> ]bQ;mZcWj*FNi`[ l7gGTa&¢LL<:'[o;JPx5yj-v2zSB}MXy53S4]աfB a?g]QJq~ MV]`m~Sj,gj/_x,+tW\g)$G]= 梃e.&5ÀB>d]cokQ+r 6ɬ/^yTl/¡ɱ$I׏׉D#a/<9O7 kǵd[+ן-ׯ.|֧";.Gk[94 R}rXV6x]^xGK ?}"~,41JrMD}pO|$ilb;,ۉF-g0IBݔG OIqyftt( }Јh :$86FB@n;CL*Y\lKDDjn3'4ry; WQ~%߀iV&6̚y&S+p򢌘P{S +U QPrS1QĵkoC˾fڛsB?"rdN \~Pᤎ X5H>Q ꐚ1͠q&s{[(vXbUDac2zıqajg=ZŠ=_,h@-R. 2ǂcN;I,6Oԋ-a#`Oʾ($x>CzSfG \e?rk uMe:RJaPX 738[|Bk$TQJ)p1˙ث%]rrAN'އUo,]H5()#n&Y:Hkj[ZCD}m ߬Gl+й5gX_Ѽ4h$dӣve3/)NQέnft KmzG—KS1͑Bx>>TBbӓ&^#<rU4{+|5QF\CY*YDS݄8I vOJ [[$A(DhenO.V;X[jI!$@';|.s7+ݡ[&{ nݘH$O*0!jƢ%.N\]#cd+Jum3 ;`&*OcD=jv}{OPЬ 7%^ S-ń6@YZ;&1 +_<vDLV5ty*I9t: GKCL*.A=0Es}iIpn {j)ݛ2~$IN)eP^x|Re3 p4a2XM]:lT8'JIQ~?bfp Y"zIfA-SSd Ll!<"R )MN<\zo/U^Wq-Ҵ? E}3Gx^Ƿ?9+wŵK.a/[eZ6R-آG2YT) t݄*VVc^[GN/ГAyM]+a {ot-G*Wl߈߲5+QZGKg4S=1г-DUM~JJ^'7OQKh*UM. |rI ;^?jz^sT#4k?Z$d珄ժqUjZM2ub#p%>YYco]bWoWLюk<1$jy bI#3.bGu$8^gSf*bؔV:jF}{]eBzPP7 Ôf N3U EK_Z Uc[WH1]*6gEcY{^+'A+#  j)m'?wxrRQWK@vi ,|i5a{kTJ7; ^9jumC,b |/0qDZ|f;[WTj<+6xBXWϡu ?/nOZiTfD4Q\ݜpKtf `O.P(дHx-9p8ֽL1΀Jmv U(h6s2[|` H楰:U(/j3|dC[Wh0.{[/BO,Z&(]gSl:îh.ϓ4;hKa.֜D7![ՠ<Qط<dvzG8풻0uB Զm*DsC2RZ5Iź^-RQ LSj!&&CB6DbW] ] M`=gw^~VA $;a_퉙Nol6`붗QL\B]In3Oנ6ثA{W,[.T=á*Fof{[kn(+c~KbiJs:n?|26^DI21"[jfO7\o6R˔Lbe82UA/70xh=| |bYoQ1T&o:ApS2q]6a,^tʉbAPnw&H͂x{OSɠM<+]T)~?pRI_)^<;\-} ) فz]2FF!01_g,hʿb2H-78֐J@ ׺#[ӂ;h  riMǃyJ8\ݹxvgRgLXu-Piu)yqT5l &yt}^OH˦H70BPߌJӡ]?ڏÙBMU:=e„ix7VGc~WKVmS -cùM}}d{H[/(ICtuQ(.L Cl1̳ätxg:ZKb$Yi$86AT}9}-,>.O!Mk8zwiEg @j$b.ydTu9׈oD{WHt!-pp7@7bdi撥_&kJ~&j ,bfj ,+ԟ4nZ}LNFܔ[Poe"`L^muNV1/@'uo# )4!aؚKS#ѷn4 K1ʡԓ[; Y%]OgI~?k2c†ެY^NLaoКX2"X)~BV9Oz!*>֦ƤI42M2i/tfWPlr| vJoa! :1~JЅ\;LTa5d_zET>XFüL5(vw"xx"/Y]8WgW!HQ_&v/E(*UH$\" ߯ȶU<@V&ޅ38-I2uj NA߿S \ Һ6nM8u&eZ疆E!IMªD]>+xU|ݿ4auWn X2&,O ^AДv n \y tVݾ4McG}-3sj>6G5*?@O=Bw̦nyFUe@J ɸs`"bJyehlxR+0x LiǖqTEqQD Z;c5CCeFbǮUڒQonQt$댲2* Z%}3 0U/%)O59[/G*5ST8§GWs7}J;}Ff_ڀӶIBነձ|$Y8Uv' X݂Ŧ?ϲ+y?#va7blNHCИA1~zhR@ |fXmeԪ[Cڐe]ơﳢȎ7` AkI&7]mky&_\bu!,{Vx) n:Toyo;e+S;&'`o^9ԅ\2][Vlp,}iʷf5—y ;Bk'|} j%-Rh8^ߜD1D*щn 7+_ځ{Ldv?(X5`9oY+#LY8޵Δp[X}γL JNJ)XxqA7M6tl۩ z L]IRyUW'#>8n5X …^m#\elZl$B}Im&Cnʹ,!B!*x5-d8舴sڅT[nXKQZKJZcL1UޥH„ݩ$XRQb< vaJXlOz:D!"[_ZEbN_^cs#Pu$<9"3VU ]\(A?(>Y\x ޏx@6)DOef|ӈnK3\ChhF/߿uە/Ճ}ImSƔpŏ?`ؐ}zw+9-{$S^榉LǠ)b.9~( c$X+6QM;C'jMCjmÌ3w|WPqRMM: |f{PD-:eԟP4@{15.mlu <_+6݂CEpiH˟ВtBlB$$Ǘ4cSqn Ҏcd "Eì|.rkyQMԽnyxݬ >&X6~6ċJV;"}w8;782Zpmh1@aWͬ]iއߖ "^ Xj.,0JJ^))EC^%'kbߎehYgR $'?gh1t,??gCiwO C bV5Xs[U\eFg"4equn S1P&֌9)f6Ь (D(MV2?O֦hbOv=yB;^['FW؎2Paf<::_eQ/I"5@Q& (dɸhߥxR҆3n,/ճT lP`|Ģi2TJ{[yx$ԾnHCF?_@թP_J>EHkeZ52LQ_>Rh0*.E"@$zm@n|} 3='\1y-*-׷MԒrg{`=!IB)-logl^4%IZToKvȷi }A*`^-=Hbrxx(]K=H@(*^GJO(F&!O-yƁ2q\ACDh*>n` IfAZ6Bgz/J. _ơD0ʯ d6ԡuؗ%nj?4S*VR9u3HTT# t/>7N :P"S|A.($Im%msG`…R&ݲ -QlN=1Ssxp^tjX &uO|> 떓`2ys#4>658ы5\u };. hv ې~m 4ijt?LLcy^ѝ)+Ec̮mVeem`Y>/.uw5׫3bHźkUq k׶+;ҮM C7 lbi7PH8HV4aH *G3uCj!F \o ;,ʛsM.n_E$Țr+!fr_|4:N5:*|vb2NjNG5Ed#tz }GN&k GX `/V _7AwqxЈ/K1Z&&En.%2+Wת7wA ;'+\,17OL*'$WiZf&9dn>RcSX3auAZM/hI8Va$u23d/W&s9ӟnt'`6T9/_LH&2$*^^Asu)2Jl,YK"@\n-WLb*i.t{M1$ "o4\vdsVgU6{Dp-2&+-Y(4c{,]7|'KR෋m {Q4ژѐHsc:;\eO:Z7]ۡK,$V,92y+ylL5ɏZdi)V0ZNߡ)9:yd5ji䇿GZC[ vFHb  9JC=9XGe)܎a=C&ᇙ"=~5oRoz^ aAܿodfۤyp~/='FecAo{,;F {(͙cgX2<"g,ޙYJ&7FO7z" uzK$a_A, `r^è h5ҜmQY Mj32q&uY֎Ërw xj'+]RRdK IǔfyH{2촏Rzti_5cMNi|ydO`I>tG12`.t&4U fј C*%.!&~٢4cUp!+%Сa?-t45nnD!8CQX+ȇㅹM;{{_Ŷl'w[}9PLL(5X9ynw)S"zĖ#nCOɖJ8j* yhu{˞Y$UQ55ӥqV,Ib}@%٧+̨4"އ޳ŤNY'trdOZA/3y^{eFQd2{VH*:7KlLEEYj.-K*F-v܀`rVmA_w :Oړ_WK4ŭXw#A6UP5PnɉB7Q9LG12[vI€dWj7b_< tOyaS`b80.}99kѓ8q#a"/ۓ ]IyPYED>h;|7v3a!2 /McoG |HJ:$wrU{3nLD776di %ʊ[䭝_y5q"^{8涰.X9noh/$Զ]䠫f}m[lйߺ{7>a`l_) /fT1.ePV5lc[\*{@#Y@ܗV:~WhX@p8 9he\f\^tRd UPR<1ZqS̰])*`ƢSjP?P|;6uxe$П.2&d*u8w<0daD.6=tݓK2ak[cy58SjPEo edEk?4\ԅ|yS!%Ŕ'k%[']JAp bN3* ~96n*.M!N#uȆ -AgA7-#wyt1luC|PiBǶYVI**R[1JcGI?pNv+3S\rٸYd5x AH3(JLͮ$u B[/^x< ߒ6KH/y+׹՚"^zWy#H`c+NܩKQ0e?PX;r$}`oٟ, +zj;z~ghR:!\J9uY%V(` _+9}pY_359]v=iYN{vS]0 }:o`%Cn?G%g@D&R×PVG整- tcQdrvb|0@.j/PGx9n:Sȡy@vTc+wtéP܌<{ @bTo'u$ m\Qa{g]Meۻ EJ0h P@zJ T)p,QXX2iSq=Zj:+ 5m_X;}]9$`;IMMtfguO* ZE#d?w:OdtaqrTL YHߏ%FMͨ$ 7DP3Zyn_F*6̆lNAO738ɿšb#vgBČ?73kgTmh}fDYpktbS߸OR}kېcgh3Bu^َ$V,X~!N3(4GxʘajfXi3?xߵı\K^(9l %H$/<ڢ0Y 73ͤ9L72@*l|6bRxq =^(o;S=2Fj,yH-uYs*,_oXGM#+\i%`R qycmWriFvvN׭ls?Q?NV9ƍDJRfwJCv+]F&{3op:˕ip0rh1F>f"u >C0EP*ߋKڨ0 Q#H徆~3V;ѦlxZiPz)ć{m8p=S7ңm_;\!)3>O9Vc&}=tj-.V!VLcx_  *=$| ۰R/^vm[tSH_!*p^U>-x0ѧB'ަmy.z_:#\Õvi[x@{:='+ {ؠ5%7C~tBpm1v R'f-=& "6"(P|0)}N8#]*9K]X#4",QJ[]}[R0d_J?CTĵB(`!d ݒh'7.n2fRw~_♟o` #RK(IKZ,RĠFd4Rf.UH@jcPJv v[FfQ%Wb]mޯ#C޴6{M6"j*[cs29* z}Mu:-g)&{gcf}v:5n m_K+Ծ*cH8m;cXoOb ?qDݥA=`}qBN-D#z&#c5_nveۭ,~°lRJ8%AДgEab#ȿ2Z ~2?>ALh4 d$c5܋" i6 ɩ`:\DS;I640jލ:(qҐ+K)-J}zS[bDXԽ_Xc6Ti0z ixc ఽx'Z TAJ֗)n=*CqiOnɧ-xE"| jƊ\nY`_hO WXc^M\҃@h,tDVv`EV Mjjy3^@\ }.S!&.Y U=,I;a g(vKhHj*B߱&sS݆ob-#g]Q}o ƃ=,49sX$:TK=_yҽ(Vxu(w֟~$ 1(SsXKwą@ '^|m1-S5ECnZp*^^G*~& \RpֿvK itK">/yRxء+t8l#y!Fc up324B`ՎB5dA/\lП2/&Ǧ䬟xl^zeQ=M` AQEFK𓄠c&ӈQ=CсMo[cHN]a s,ݳpr*I{| oBdA7TEf ߋxeM6, zb FV,qH ݏub`ѣD0$Ӕ^5,8>E ۢl!;$|T*H(4ȵKU b3 L*RVxh2E!2T V Ԯ/P&YW{8HOB)jڿHu e@l?\EKRj4uuiM\l"n0>D/ZwphQ`_"O؏'ZAB%ov Z#paϼU 2* jYPDͷWؑl̮95%8Bhϐjd 8`/z!E&udiN,=dFP € ͵9@bWkE_7m~^B7Sj[t_oK`Ep2 ]oF[I| 7?Q4 3ÿy0 YJFm.; oHj fӂ }~W["PJ(s85QmM-RkpN2WCrMW8P2\h/ma~)DaÒp4ްOFMZCj$W)0$@2jnn ;&1e{uC).EbGuo<8 rܖ|4%J%X*];{OДM pe퍅g.'U4gF{"+-:)I',U!oI5D5 j sI+;ӭ߹+=0ŏ'>+Fv?[ֳ6+G٧jJAbP/8-!N{5A9F;oE4Wer xRi:d#Vܐrwo,<&ѓ3^ )8TpD+u%,@tqBċ9]#XBзK`y%}Ϡs T4ڢ4vy~%/칾r̯N&L$Aעym.q+s‹jr@C cI,C3Syd,g]PǟGlT1¾WթFeM!xϳx7"Q8Lb`;M05Hucp[EφzX#9;;w˵_٦+|x Sͺ'wɏr^S9K-3DnF=?xЗ4uN J6&D9fj%'Z%T~g)4t_)MAx?DQn/a)W{I 4Ήi$l=abބ(aI4j?'K[.Gsג+^1MCk m#3hLHK܋p$:\_ ̕B*`kY ];X؋ O7ޜSKn tƛ(rq~:<ՂO$ixkݳ'8 xn9 P7'“ d*6"cF"w 􇊮꽕{HK? ;5e`9nt^=6;f(]Ė9ܜ<oMM(?y{0( %:6íhLS@y;S0vofV%׼dj(8efՄ5+; ~Ts Ac` ZNLRUQ!7z /3 zI#4@aڵXZW vQ> d/\d&#N)l74Zx4VXbϖ+eN_MqԘ*od_7w,ٴ".8[syO,q >RWJ#tM>XΚBv l?T±}Sy5=]zM <]振`=OwA4`7LwZI!mCHId1G\QP&YDpol* Q\!5uZ˿E[#Qu\.>Q ; dz>b"p(/RPyK9@/@XѮKJA,0c j5u&(L\+c.׉тn{[tDKFž͒FҤ4e[s4urڙ4o'Z#5.ͥ7űz  -1xo q=E:凓.6b{f蓌y& w&q~jٮAVtϭvsbRH3)͘0~鉶|/a Ww6@HMU gv9gF^)كӼ2m GD&X2ۆ~s)k O9e@faԡQ{J\\<{+O7X]x!%h2#ܸHTh\;Lpq0ݸ8e /q`fEb M2~A *G1_ 0#]3܆Y3  X'[] &2,\GKFCVMKLEB2wg^m0k$oZ … sX*C V9l;oYtʣ%6Ҵs*<Z%B]8&Სv}*%im6_fL'CT IfsH.`䴊U$uD" J0?X1Ur: LȌ2z?|.uڊ́R[KJJk~;=2 aRA&J#jF|c\$U`"4?.γŕ&7ӵ~8 y MIC e{ Ͻey^  - #hbE\/l/{5[窣չ6XO$H&o\`@nۙVWsO&7OfloBE)@)qR2.â_b킢v 홸x皂tՇ,|h@e?f)5T="+,͢a7q:C'+0!m}p$`}pR礭-yr*z+of1Γjc˧ aqKc^9Tx/Hµ9oMNp B>7 acuoÐNQZktaKh;cW*PDP0SbDJy*68̰*x_Zc@|>GpѺ0 571;ݗhLHN^t{骺e({i'rPi/9>FdYR#y +e6sGYKfaz@7Rî{]F~36ܯ's͊\䗰Tkz7le,kJwKiˮ[Tԛ~p$p&`سm3;+] _GMy&ܲ*Б ռ DŽN`̹C1f &37eA?EEX[l8t(S*BBvgD'ޱ,Qa1({82o.QT@S@hc"~nLE|M*?L#$(&ک ӫw]s jtvkCvR[ល}X-˖`Fx̼m-R*T?=pAB(dS;^k@o{Qϴ;jZe'8 n#"f{׹{ kl XxȚh^nqJH[j%tX6 *f;>= Im=I.3))};a}E Z ǰC_|_HSܜ/l $vvrLctQBbm˾5džaiSwfaNbV!?vnAf̤eW}AJ+Ji*E8<'ÉRzQSQPT^dImxU]*XI4]@sMw n I7kc9`]>u^{{UX{/ҫ[뮦* fĤ6B KXoI "HC0q]iOOڼя:2IX$=\M桤N;31z[gth q*o$-~^c\Nw$d1rsTBaXv1(D iD,dp1I,vi€PGVH`U1wc^44BZL^?g5f)ovQ"Vo+QˢTo43‡iWiƓU_BHwhLB4Oq;?o,х9CC0B~o2yܻJ2&Rםoh>ۑ~ewIkL_M2oBrG3\%*IiF|h+Ce7Mk&xX`Z,.L9/y}k{Pb~fmRfH:k'ԫU4_ \|B ?~ b Ĵ!=F$*W.Uo06[o6mLG@e.&ш֢ރHA"Xc6 f6p8s#0uT&*~apSRkT_yh?%[<-#*:&C-fTnn"Pl6U`úqdOjx~ Ht$EDHJ͍Q4,H \_+v%l%2|> umΑ|>m){PDogZ& ׫~HΉtJK*s04^  _DcU(bI+ ۛ:C+(AC7@dsIհf9.ޏ?Pg{l7crH 1R^YA@ĺ74J܂fuIjYGMZkg7_g}eE۰6?>{;]=Xܣ{HjJB@mY ,+I"L>:k:dTOcىt7mII pDY<չK$*5?*կ{fa/M"v_ane6Cc[O fv!Jƻ`fM‰\M4'vmzJWG+ˈQ2zn'RN8L^EQQK,g]ɼ j `CMKYaD>k(c=4.aKm'". +z&Êǀ}/P!ͽ/@qF׭ʞ.(QjZ. ~F][rV -Um\ݎ,)VqAptZhkw =J|S?ު#9b-8EYp>L% 8#rEL8;ֳ"λEєnASSnkP<ȥD&& m/Mo1y=`~R|쎻3x;6ZFPWMLD?*8fyR^4,-"H|5ψU7ED,e8-I`o;PB-=3 Uwj&7SSK/ -$]c5 @MÇ.+Q ?afh-9e|LJ44s{q:__W#)lw*nxH}/iM-rG2CPV~4i]:u'5aQnas_Ca/EpGN=+R#:͢j#Y =1Ҡ%c(,%:t>Tٞ?t;H`ć4:C89:ˬ>SЍ>c:ZE<UC?Ct:`0{^Oڤd: BmUeY_{ ToԻ>2$`&VX#+5PP3D&+G@i5.l;>-GAsQ. Oiκu+R2LTP"nmdO.|EJx@Xc IDOS{?Q2?K&?6rNkxt܊-T ;fs,i;y47,òN203crMR1oeq(hCb\z1w@&AJHgj!ƋZO-_%~EEe=i(w(0yD(`R5D,!XIm0aay1+! xٍrМcL>ڥ Aٝp IXQ~W4ĎV 6m>v~vojȾ HB`]}A!#ISuqYPl˂%-0MS qs zuM-32h"[@dpQBjI]5_V晒LRI`zC:{ZgNyNWǺh,aT攪8Jh_>g>M߭Vg&-QquHr@w@ahT(Y2UAQ6տ /gT컻WJ+ _D(kj-ve{W;B@|ב:X/eOͅ6,/+ڧ8kH[ K|͢nL p6GI `"q0uWqB >pۄ6kLI? %Ij$ҕDw%+ؾ|i?3b Ģpfm԰搸p%e]jDn*fz6KuK{9i}Ug,@S~\azy:^^a5.!-@Ѹ؈v}k5*I"5HG4WD.]nȨ(1I-F:ԥ>1!u:}‘TIטl8;::8u$FEwYg+B+q:lA㤭W8RTayv^qhLC]bຕ\d)>/gi[ˊ t͚~IMvu[t~&ͣ-΄6Qb .EFqN6#½h59@7 1oe\bW7(I"YXG}LМ%)yB3srLfĄڡІMP|3~x/Ks k*YB92 ɼ Q%7Y_&9#,rR-5?M,P-dOFsy37EYI8WnBˣAN>.usd*syG9lM ,k]׶2xlGY_q@ewZ- qkȖqvJCR ^+jXD7I4&p;.xrwv&Cbk9qswM0\6 lA}Dfg-Hznm7lI 917N0UՊ͚-8e%VI)㦕l; =ZBՎʞI^Az|/Dq+햣Ey* t8%40Yf5I^.TsVEaG1< )l1'sz L0"8E X 'bFwYt"8e86"3{TR x훭WqxAԂXע8Ŧ4.SiŒ>?ŕD;4-Oܱjcy-oi6ISV#c?ش7\XƫhYߧo,60 J5/8%3XI .LL1TOjҦ Y"4՜"sܛ5?%r?pi( Ҝ /% ;mJcz4 d/$"*:[ [2$B mO\V-<+vJ։ko*NҞ$UK5}d}'RSCEFvPZ5B4tUAoDv݅H kKK[$[s~1DJA+Y- _8׋Ŷ~2;f@4^)-D) &nk! B5A4_J&}gHmYߢcB= SnV~]2$ތ3@Ke.3,˝xР}^1mM2L{:8܋@vŶ^0 6~el93Xv7s1zBUN кaBlJQ/)P8#TdOz*p=dO ʙ|kM?v/n3aݢ R l8ds̐-u+֞Y\uX7"|bԠƖ[DE{Cf&~.qԘS`Y_xm ֮$Bթ\y󮫉ї=-G>;'ކbƷL;w9]MfekH6Lv~*W1dG}m)Q 7IvmA;(\+k*b{li 7$devG&|JU`Q*Nhc>QZzl mY;ul.}Gh>Ԫ>G 񬣽aZ x\y'Z9{`j3 y9~cP؉'Fd'@_#0X,Sm6IBKr[Ȼ$:ҢӹlHї/ʀ7拧=rK;Xwf y趰pn[@L|.-X.Կr2 o؀ODD43jW&lr.l9 o1oH,St=+PVf+'1qʀ;0A{Lrr@6qX UYL>mf7xΫhlǖD3Ӟ &0\ju<Ӹkvah@ N=ߤX`Xꯝ+q|0KҰ^tYXo{vmա4Yö]?Nh_ÛSޏqh"wp ENxc&m; kߏ{xQe ڳ}H= b p.^ IVa* 5>"^_(a] U|(I/ͼ#qAMC SmsH IruV]z#vH))mI!4C@tȧQf+ijX!?: eM} a gMPKި&iIaIEk=lىPȼ23a1/#,=/SzIhZIm G,mP>f 4si3ܒ>|ME+U''4c!nRU'BgV's)LS߸. [|7iSs5 p,Q'3dX&v+GC$yD+4׃2EjW6eˁۺ,Z 3_2fGOKJK)2Xw54Lpρ.N{_?7 Eb* cRhfD `)I3lzs5Ɲ`<&P 04қY(gOurfwYR3o9=_cў!=r8tQ |oȱUl`|Bۑ)=< Vvc L3kppu7 %->shYhny\Wha7$L3D/Ytw֘v)d(58к mЫP`yzŲTuVK݀6Q76K^йCzcT*w&{,s-/iPxA%|>O[_Tشr%Oi4ފ!'wg gQ3Z@r񘐁H* ^߭弳UuW :"DoLp*5,@":X~E `zEnԝqDo ;;* { }4b1fAnMRua.k![6BS7 ˘ .JbE|>`4s#3ԹGEr_tG(IW2r/>R3 Sg5@u2gtJO_l-[Ӛ;jj]aTj+ Q8)Ag0zJl#Bs],9ҋpzX*qVoV@;5R R=t9U'F!7T^#Mȡb Ȑ|P@ a 8S}l[!9EiӠ ethӊslE^\AyxOH &#-$JdM%t+d%?'Z`yL?dR oYu^Q-YD{hȁ=|˕rʼnS6Z Z\CWUaYǡM='?ݭLc_,j)աōW 6C7P~$M L@,ZIxsZbrGy9}61$9u 2um &ɂ6wG V hE]H (3 MSng#z$c8$(꿬։ckc8PHtL aw1|(-faܭĉVMPƣ+2jϛ7B>ʚ 7C:Ikr\sO.C+q#M'3X p_}TN)񛭦l6Rlk(RkロDN(yH(r[bœ\G ƀM<9νT缮Fe,X89- zf@M~B݉Ȩ phow̗tTp˻ϻ\.1Ƅ:X.A $]F``QABmk=ph~jqD+?$oGJ@9j̬u:VK9)dǑ¨vK Yn{Vm2yhS^Vؘ ieh;"X oK b@҄07r9720VN#IT>Sxĉ0+T&5dp5SkIɹW4 _94óxp׎N#S5} } צs{f0!pd_d;T(L̝qY} qm _HL{2bu+ )?^xMn6!Կ7>*9 8JZla>jG)x=?roZЋOP/8mzK?@r #2(z(au@-o\CefhëވN<z|*xHQ<}*gOG!tHngիo~Y+8-/mb@;5ӬZ,})ւ~Akc-HgϜ/jKa=e+#6OP.FQ<'HX *Mq{Ȣٜy9E r&mLZ)\""Xuevm V.G[ƑzK[ ,f\OpgwR`;A"{B@ g]al-.\3Kڇ}\ cFUpfdbR,;ShX6~g`Z._yH q$l;Tܳ"^9%AUV-%..a`a,϶L9Ю*W~YvӧDԖ!:$\,8'9Z:@*uXܴItאr3'{;"lj{#b -VJx paZ]OzdY @I>a]\MpQ,-]9:}Pn=/`\Ǵ!1!";b8E-f'b|*6$5{[b);o.fTfF~zS6 y.h .6kB pVyϥNŹ  cHxJ  ͈˘UҐ Ru l4|C<9o`&.z < [QZv6_Zɩ:H ̓s(盚sr&{TLVuspr)ŏWnzeM-V;.$:Bha  K!GaEH$!W"&5+yA!>::%vyjq?Ђ9{*cQiA &oZm3PthVx4gYfC=1 x`ש5̕!sErr*P"/O] 0Q:4(c긽Hb#O s&(~&q]ްqQႯwx&lGp%A(BvdTkrRo^—ؤxWKW]ǝq4>{Ztk1\.I[w 8R΁L\AGUCU\;BVv#@wX&x]IB*x3|&$ҠNKۀ\6)"C !6EUMc'9~vR^B\tqhߏب@7 A =RXxV㹟@=F,}E$WQf]Z3GtD1?=19>f5ƔUL~(,]91⚕x+g 峘5s]2:c3uVklӱ S! ! C>0!3H-~>] *6E|j<7U!x+)U_٢eh+dIJxLX Qz *fDh)K[S#JP]C|Sgbݨ_ ah{@M福`mB8FUB( `(\yasjɭ> MBQcu:`>Vfo"t%C>Qƃ!z= Z=v,Cp'e~'PE[]jGΛS*+OU362 ^&]NBRpƢlZI ӗkpE48zR7X(b6Yma,a,G:߹тkY?k4m+}$4_"wDŽM/vM.C`rn-)pu΃ ӡ[JV9&0j;RdZaWԍvYt K4=5_8LSyz59&N\<KX0DGG/Io =.*M,K|iZs)v8o,ja*lD%L1!S`nq2!ߙU0SCv"oS"RRY&ylA( ̽Juc-KK<>4O=(,T<ԩl,-_|gE[fPΚ]?IfYW|i&,Jm|07gLǦڱdJ'~METѲ;Ց?,;lӱ5YA^"(?{*$vJ֙0w#U]U'槥RNnGk.I=z%`g R/F[J7994 I7umVlFHL-9i/_l3*Im [ʇdq]T ?& !HĵSz|n'.l#C$e~ȊaJmG0[zNӧi@Oyh2^4餂jLɵzlҦEjYO\)A·@nӅkHKp׎RE/+֠# $ed߬$)A2*@oFiv 5Q^H^} 9"C2ؑEUܻ[O =Ht5h)Kf:,vEZQ VGp4X"dozsJZZxXD$:!,O'woŕ; N:DiTzG>*vIo.0^uAkcQԞ'_BMi9,aX0aY>3&18HX6@{=/][c כXpaTo\~賈t9m$!%Nk KX9?  Dy Qp>hK+NGH0U%O5w?:?2og?V3g8|fgLx@6^c'E{ysZN̥ٖJܤe%C1}L ݹ-/O;īwx#͇P9}Cf/'1m#%+?R@<{!!dK`Y@ȺeG7~Y2Rc1BvkVF(tZ$E@Vj`s73d]ID 'LB o675 ?w# Nr ;GSPW쾸EUm̽,y<2X;uo+I_U hxd%7̏ Nmy ;қܜ aU\s&SOE9"-7i#dtK,Ҟq_84Bw>NX" .{Oy >+lH rB$Fԛ-rַuw m'`vxMo/0t@ )pGAE:4^:E6q"*8[0%ᅁcqv//B} -?Y0Mf]S KW0:)Nsu{EaQe]<{]jhp к[;ES]A9>xԨgL`2X6BdbgsMHa131jl> fOԊ*`2^ohɷWֽҾhq5T/BE<|$&w }}mAjxKceuTxyvիͳxgNT^& ]1| Y/85Djgζv_vq XEw,Xz#m1^5;sXT}qi(9%/L#t!X {cC q,EsO"$H"<ޟ޹/P|L2H?!FfaJ]T˃5lK-g1&w]˷*\ٝ||dm{Cˆl{[=nا=7kfF)[W!T ƅ8r$ўg3 iGq;>%fqum@pFDAJXaTo3 yGbJ>[gr545.S) |AIsb8`fN.^Dlp;*[D!dp;>v\Uv"1s-Vw +l͊"*%=iPTT#7|αqS6C{ Gp_lefz҆fԱГ’}d2*5m+0oH]oT2Hz稪傘)C\R;ZIރ,ʇ-t߰)` |ׯڔ;PS?W_q!H-3$J@@~fR {@9KEh,; b}R֌\TBjlX?LɛpClS_Nb¿L'9u>Y{% ;sƨRXX0#˳s{&:=#1Z6y`M?.C%RyȫX]b[lG5I ͖KJ y (%.vt<@ŸYX݄و) ۩(P'D9b+h#R$"4"ODZMu&쫹LF)˗a' +ye\U@zc+4Klc.|ĩ^9jNX'CBkKvqkYXۻ:kAK{w{t7T2 LAQ9l[EƖ7Oݥ=ֽNWC65nx;ShC- d +@h8|5 $ XSKW{x2އnfOJSvwۋ_YRlo;m1AOl~6{_füJ KbtWILq^Ć{JsSQw=7ֻͫ-#U<AYy<[R􍋩9i*9Kԏ\&TI*O|lc2!8D~m>(kȖ흶?+qkוU!sp%ȏ)@|9[=R/WעUD1yu 㚓!r_i='/2+6B m`RtGcڡ!s W=R}.bHvPЕ{޴hh2y,)5@\$wvo.K뮛:O1dz>Ij4*{`,c EM(͜_n l)iQn~%?G]0 Q$Fpg‚"SY5|W?#h]e Ur@Y(z h'4U.d2Uʚ)44b 75WVwhY&+ĩ/ 7hӰ8lP%aKUmD)V$K!stc~hdZ'iusb:>jrؕñxĽ. AoI[I=9ok/ ~!15XhΛWKDqc*\~x˱, }jɔtev1+<ntۜ"_Yq)VEŠ虚Tw8 >OOhχ5a$ȵWX}Gvj( N!;]VWǬդQ k*0m3inBolYT*{\)jU"14Rی3#Di C۵;8|5wN2p; eE/PҊ}aD{淡C"J1dr1C=x'}CpZ;szmD^0[{ L6+"Gc1{ݙ_,Cp YM(yuyZ g< -PG$6:b_qA{2~>n=ݖ`d2߂ͤRS% o8鮰[H!g[L:U>ZtpFxN-ĜWevU@l$-̹UFwUy*,n9$H~f]/}/1iɵ3nDsA ztFQ[oC+ !>89zDs?~ae b NTnZs(VhB}y@ʻ1OgCҧ?_s9ʜeoL *R.4fxaI(ҏeHPc'bZX;z\,2)]6Futtl"|Hiļ^KT_ ?p Q$Nhfqon -$;ŭ&>0kO+Q&!-lL I:b MkNYJ9uLoҧfK\@áX49ÖUp Qcc,dZ6e`bꎆHЃNؒi`KsB%ʒ" JV@%ZkHH= tOo_t{bnq!58tP>o3-~Q$UfeXP`zj2A0 W eCF îԯGiT"JuE ?`F Pǐ>SC%M֎c#H[\^{A&Qa!k4fք@kW7qV/?D)[0 0oQ`AW )CEG@6_Kbr 5!XLɆdNIT2^;o;REQ7̲Z⴨Mhas=@&c]9(%Dj_zfjk,3dRPkoZcկs'[=9d5J z{Q VzJͪ⧦ +bt\j"I2DE0YLZjQ\Tg1;-2Sjl/s g񯯬34,3F5  fPǚ@pob =ςGh;!#Al]Oo'O3ryAW*V p\i})2 Ǘ|7?xڣ-ۇp#ƚ/o^e2h;nhº7Gj2'q.vLRf6j9 KW0[D_UŃ LGkrGnF4\Fm.v]ڸ0$4UVIt_Єʱͬ.D)ӓN:+䴜ClZyZh٘WN{ UHV9iI{U]ٯ֘T|4Gp(×uq}_bp]xzEkʣ,J׀6ncwAP4/wU-4_,|S[ @6q .}Բ@X2:9,5p]+/nlzG,8RDQ:Y,FCjʊzP#M^ XCLB]G_>\1'nÄ=|5rߑ+ފ;d`9`@ 49=B~T^v+@xp);,w?xY?(ӒxE{: ;iGj4R̈́Ƭ]Kڃ4,zGȱYʳk\Yhvc4+@vlGkޫ½(K)f*:ʶUuBop0vHK>+)@w= n[P^,EXſc{ݦ'k 'h+̙Avߜ @J|ay4Qr <-6:f~ =uq"z%e̹-[i SKz}ۀxd=Imf9x'YUr ?H*8h*JOmy% pN ?Dq%̖:IvL8G. { %%d|*D`-/I`>U΂U .+圲RT3':#y^Ԗr̜U q;&,$YK-:؅{kͫ_spV,%T>PfsQiE(E%/ѱK~MU`h:ù$q2QN8gOexF6H/5 ;ϩS/E9kV.1XD |$V~P // EUnlWmMPePKMmz{_B{ K5 ӟw g&Q Xuc7Rss`:/#UlJ``[y3nQHH5O;9`Za5@1߮= k\ʱR>+Vb}w=ʲM4˩(ju9RRёu;J%%lҊG)t#aB(95nj# U  uW^"C7L:ͳ̥kmh al+2%g n (㑵^|tʪhwUbG\x)>@[v>O<̳;*w] g?3ň 6^Q& 禕 +Ab!c7 ъkakwJw*!oBUE^%OKyzTvWZ!{} 2SW'Lժc8İYu~ evqR?r~H? FEoZn<ၺux Ha֕0c&2( #pZy Z"SnBRl"Қ@Ml uZhTxn,x䮋{Mj(s. 2)iӞ4aŽ*L.~Iu#B-yEo#d}I@at˳3:T^f,6KT#׊%+?ZGC̦b3u4}~o5i., S>ȣԾGԹysChOj6Q (Iz&yֆKh-Oq~:iI(q I{ ꃘdFlw _+}#b4=}rJ31wM}tC*X qC:#mdmJi,icmV IbWP5/^[!gBTl GjkAɽ sWٽ 5vbTg^m6C} -V$"-pH$bqz+*dZd`e2r4_[!اJ^-x=D6)gLެeipzZI }.c+ ?,1݊g z7AbM|T{٪{sdؘĮ~liKt1 u-}&C;$[ Mr˻Ǵ`i69N<&rP7j?@q)oGg4p>2*=ȳT;/!hF`^3X &2 hR}ܗKN[:u#[1IoJzwA<L0W Zi7IfbQS35`>r4>LՆ.8_.\Δހ%VRt4wq*:3ug;Q*Ka+SqJ8fgF}&eL 4G P! :|1ʫU{^'䫌'nD_v/=>;gݷynE27v6Zމ, ?eytvS/,s65Z-]IGklPYz YGLƻ/N)y[R9b@pX[-Y&$J: Ln-RBj330KPRYSoD$Efܥf`^?6tbe<ʞ.vfmO-TpFkQK5 4WgC*|`ihNC ( Jqc% P >Vgx;$i v*'%nI=Dl:q#6Jt= !~v Ohjg.[WnRjDSѥ+ ^qb[:, /RcJLβpzݦ;jٞc SO@@5R5ХmW1P` W De/ƜġPNa/E~_"jQm]xFpVCH[`7b=E L,d. ~.5غ%jI]G`ސXU؃0 7!/|>E? OP=pd>jWޠ2n73O`:!,u @U:@[:̤[FA*' /I|O* *-C<+2mGL;YƚJ7)(YLZ =Q+koAǺD@c%R"kc;Fϲ/Iq$T129n-PC&sfM?ҏ:vЖ`d7;:{+YHu=#ǛJCЗ]6Ti~7E5Cu51`\F5<]Ip߄> |HP`k~AO]S7&]GPROQ_rQ-yfx_43'XJ.ɠ$qeR@]^ѢVJYCqO+9?JLP"󎇌a_^ʭۡw-b1W j )ha¤kYiŰRsU}%R:&2Ss#Ά-*2վS1X<ޖ00h\WBUs0!E)q nY37kܒ*c HQXP GKohvի>xTc(9S˗|jnGEBQJ )EG˷9~$+.P6ōᄐ'E + sr26)0]P:w2,XZ4CQ 5"me5h;NS3ֳS3Jm"'!O`Kf׻!ך볍B=nX'wSN 4b͝ム*ņyw,X˪࿍ ~_D] n$L^M?`ȣWcXI` 1s @ N.> d~.[#] R{ lb DHIKϷprT{HyO(q^#QvL( p{b&Ǟ>/©-3 b>\qOy{UZRe*BE&VF~h;_pEj{6 _\8,[¯ ´P\ >t[6M0)ڻn8)W A'e-( `\B@1IͼQ-r+3\n"r0pfSr3ק($ F[ HѺH ¨2HWΊ{wys(l>&L9{Z6MOp9hvT8O 'f3:B~hdc')a,Cq^E4E7 庘KlHoIE״vyE^<(E JŚNJJ$!SϟGm`5K odC$3 yoS4 NEQSPq(Cjcӱ4FO[\\ *0UU DW¼Bf qN)2/ٿu\1@̌(=: rWKLBpdm8(B1}SO㕏 ūC ta^h}z*-Wkq΃SF,1"] 2#1 ,tA.R|Õ3C:GKW\]3L)RU>ޫx[3KQfrUsՐB d.?ڔcif.2չ>j 8i, fгW[4߀T x3镒[Lq!"t5^MC|4C0V9CjB[-qϠiqi+*B,kS@hq]+TpLH#s#nf7hq32JɟPH") ,jdꀁO(GW,\鍟m+YH}-\XE5,,&1ȶ4B 0~¢KMľ]zllA%jvJI<}SZM|5)-iסi=N_ѹOZX>M0a@ =1q$?d sDGlęS9UIMމE~rB0} ZcZg3Y\zr5t 18QC0(5 wgezMM qk{s+ U(A-^\w~SnĽ3O@]qqyqX9߄*;qBkK5SeC?s5ṯ\KUPCxnӞأC"s ћX*5ʻEC)Rt+D']ܘIYd$h/c@]z9m].¶sv20*:`DƊӷ6p5duEyTc'ox/KbV6,_)VWʈlU,QLFv &xU0%S /8uPx Hno01{˿Bb5N_ukјi[8g?F<&k+LY*D5tcoINj@`䐸/z3l,1M^^Mn#%y)d5/iɋ[8WdEz>~pQ,(q )cr@2(jҟk)SHA%> PJBf՛Lb5'Hn_w y}*+B¹ I(]_hpjj:V8s8\@OSXsQSg"6bhRi62i :EJK8~wb hti*b 9 >]xl1Y{ZkQpP{ Y [%'>"B]l;ș>"}Ka ;D'[bȡ4Bt>Ve 6>؄xEuoJ }Ft7Z_iN,tB.DZfmuY{z{'tqǃ7@K7̉pqDv&Uwqp+Jvct ȷ)~X|m{cU9s;F:عC7Wwo.m=۔ozU{/4\*VN{]P?ʔi@U dtRH N2(%P&ֲ2S0%;AT}|$X~K>W(`XX#Oиo)`3:}D(Ɍ{a>&~G&& _i=/qW1rD(;Bٟ U%?[gn ?Mٙ!~acaG3ݔ5y`0,ʸvŊEd"]җ\6n[} +0ȑ'}0Gc(3E\@$uz Jv Q;N m9"X/^S৿ w]ȫ?PĜ'Q&hi'AbZ:-6NGmI6!h}>ysp>WQ9jƼc4*N_CNK>рZJ.F'DpU >Q'#Y-1g2yZ}GQKU$;J+"nЪ=7> ;'8J*,q% =.Z~6 r(7yu 8ɬ}Ƶ o y;|T}rl# qCTs57dT4G$WKԟŏO~9h xk,P tՂ? iYkRCRУOdBcm''PI!o)IbF>1 EdQv$jQAbѓϊd[R~L}ǣ?&kb̙s NY8s LJ4#ȠmEbp#azh&66 -r; )u8'Ssv褵TuDpPî C0lXhTz8Q` Bl:ʖ\Ջ4|Fos'h֖n%,r?h7"3SXCUR()|Jݝ#@jg<>{ju=m~۹DQ\jfs \yj7C_T_*["Q띏=MGqi;t7s|ٱ(0P=h@}\h3*ij&Q>}{Ϻ>\g9@^1`kgwf%ZJ}T7OI kL|nئ&z*Λ\W{%p7CI>.x)&+O&yo8Jc_g8H Vn( sPt 3^[`e֬ϋlu%T[ʉ8urȯ";"\:5[(Qx)S3_ wE9u5n1"_OXlFC]2ys R/ϠUeˠ5U =[D$n2؉Uz @,E/7ݗ$( n zyJ 5O븙 < ΄7G`EZR#:(8ҥό 04z ?J;&( hlu\XҼr7~Iڭ¦F"@(;C 8YAfbcHpȔY\]ڐ!K~p(HS\iR}[7hUhdlhU !Ւz_pX m{2:6q+׫BO)Sŏu1 S,$h&8) IGtB-8p|T'n/NNq\%^'Bfd, ºƺ gSzRa#u,hriX>@fm{ -9U$s6uĜ1Zdj8LwF"9:Y| ӯ}6ߍqT"-[m8ݞ?F͓6gmFD+aZi@IOͶXܢWHĶLq_{SA>{"PxbQS$m*Ęndvq{Vu9KY*l15\NԀ%8`FD^y4K9!)h3ȻM {;V#ouV.5J:PZږ=?T d(/u~NOLd4Ceͨ$0%}5ThK= --韜(4pjxz8dhօQ\-=2օ\ri22p_3o?ߴL2bMKrU5̗8g..p"]Bњ!Qg?T?#v]yٔgOǷcfqzH GKXǕ=xz{{:Ӿ)LtË́:#{ &X,<*$n@2”npE1g{ K$6=;h\-q 'sau (;p߼~ ΅E >oeCQ!Ӏ"{j7}0/0ɚB+z"hYS]{1:7QS9 fl]Mz @_ς1/t͏\ +o6(&'9;_p)M_GXFH&L")zbuM;a9*>{hod~OIAP: Dv+aQkf/tDAxaV_;Df.)_s)jQc9s,8,kFiJ#CjBR V`1|pT?)u} Xt\dPT!hc3g'U«.T(NJ i~ )||#0Zxj GdAbI_`8=7 }Tu)76O-oY$,~υ$~P%,|zıR sL GGxbnK cx;m< {Ƹv弈b9`:hx_¾$ #|1M9j a>1 E,^pa;uf r 21 67:5!w9'%_+]šyIA_KV4߰R/'_ݱ|o<'EE_Pc^ӫIb$'vt6Xګm*f @OR =~ڠT( r2& chkde{cԒ>]%h؅N:tx&ԡu s_&`B ֟{2Ou)> ]Ss;9>\;P 0c ғzӨKɫl$DfS4M_ /" 6ηT+QN0l{o(]exJC"UNw/̧_'l4=uqŌ[ޡdCwќT&Id^Dz.xy3R!،C_$wDW >(HqI8 +6!jewgM\*1w0LG.8E&od,7~}?atJ al@<>~ڗza#A _W{Fd@Iy5fT*? ]|uZI> b%E]MgaxEh0I1qnȻtIwhBvwJD3у=ҋ! H ^/O[^sb .}MxaVÆV \.>eoɽ!(N$jbx7{Fz133#O3^qsp{!`#-XJ?ƒp:TΠkLc |,|+Tˣ9qMyhF,z8w vyvlxRU Xzs˾!V!ҬSqafί^o&,-\>$vp0&yGAc *ǃD$%qb]NE=vh$"ewsQ: ;k&oygM6-g~'anԱLZg4C 4&fhHDp8zTxc֊IƥbpPZ0[1Ž Ž =<%X5mtd^-8qNלD|V(?f j v*HjV) yBKڽh@dbt4X Jx*PtY-mKDϞSP]~_'boPV_@oCFDJ=]΢$=8;#$uy$ʽG=q=`C2eۨ\UnaJaL5* "} W.Robٮ16ZL5뷸vUrZ9ݺ;5 HQ߻P0tG-*~i1c5C™ t`^3zHWb p<*Tq!&F|c݂ܥu/'(rB~s%}ܡCۥ3$HYsB.UVodF B;{T/HjI!vb ѯCfKHv$ )%^?ĪҴOZ Tm3 Fr=o: ٫>{Q$Z/p6̘##h-AJLn$[bH@m|׶B-v <p lbN)߯K '<˩`?4wMʼHh_h~fgxE))pbM|% 8f O0eO˸hX=fjt`ruLW _˭?6 ZMq>aGA#NPz4mDyǭ`6Eps6*=!B8C=Sas :B]{ܥhFB2REvscc 'zyfm[`?Q]󄿀/B\RNf0.A9 QA fwq6H}7wC *p{ߠ݌F\Z-WDӲg65P몑s]7,$YZճA;h{RZfVa.FN ,>㥓`6{NIaIƹK"găVo@33kL^S{33 vf: " ['mpbjs2xz r̈́]w&Etm&o硭O*ds A:÷\P x` SWռ#}H/Xd-IZcу)$r(q-4},Θu jWz܏B\+\\ZF0D6aHΏdGjB-hTY a&h 8c.Eˎu3{OB7X3B'2BkU~-P`8G`ժ$%Βѵ gֵ'fA0 !|8lrkx=)*&eIsN|]O׹/`ν Kex8S:{,өc |;TKs͑s}찦C0)6LJBpp f7*Eǀk>u)0lv }|)Y*߅UQ1hv:P+SM> uNOLJkE>"YPnD[eFX |Q{r ˩ Knj߹b=sU^?PU6ϭ4) n,5ϴ+Ph'W,"  <[ǪxvMeK*}V_#D^{-64~ۏka0Fa&ٗ 2ZZtlˀ LۦLCʔ/;.r1vw~\j3'g[80 9 w/fp j݅H%]I{6S L!folF??8fJO><$𶥅-nB#8>6 xT \{#_*\^rQ&<;ASeqcK9 S$:9VZmEN#VgKlD;){My:$lC'rV 4;8~[d v}Sꀷt2D#+mm*ibG*<%)`!&;ϥS9{C}q3Wﳖfemn/ظl|_6-L}_ f. mSZ,$9&j1L%`)rxzFwhtSu$)\Y(9(~ݹTaW;c]O oǽkho+pyvAfv%p\GqIӖ< \ uk+̓,Ͽa(\{=RM,޲Ư#壄Wzڜ}kK5YD}p M"製YTgX,b zM0}1/9~vn jQNX5Ĝ' S8O;xz(鐠*D,wu1L>۵ʑ2n~}2:JZ4'u6j̄rUy|5 m{o\_6]*"(QK}A#r6מ=}tn\nSM{rATT= $%1.[_WW^S 2Ci:£}1|"NKظ7h~L:b&n0cT?: =EY g'ҌC0E MT,U@Gx y`|u ObLa`҅[B/msU*$(o,%apoǜ<)fs|d, A l~KWϖu@C} **'C4x)D}"pT4P֩{B('_Ue8VԛۿO˲g1 y\;?N4[ kWKn@_Cpcl,\^+cvjHɏ"a sf[ysRU7Ӕu} piMQ'XE&3(S;cӉX<)m@,Jw&@4B.3K|ݖ }g=^tZ Mއ]n !0ߒ'}ey5 PIe0[4RTȤVfIw!׳8)= xm@(.ٳզK|mu&oM%̫/GX/RE<:ZL!.+lDZo?g^_f5q%jKembF28fD%Ϲ+xox1~#߈nӐ;u6vR`Xy {NB HB6 +~i #y"κ:tcsϨ5\3Oُ=G"ֈY<yG݁IlG"`x&gDϮcA%{*j _{PG$2|[mF>ITLtHJ3Y XaE /9n U<?t$OCf'z0)!X*C,)' C3tU:r| 50C(CK#95"7h&S@r30>C$pXʃXtT#/,?nRM _&NYB'K;or_Q/>{R{4kUQ]_@p$j>2 "6Tq3~w)( @P<0dtDv=d}=XVjY[:=/^6 6/0nL/,Xm"&v3WuVXw>n28X]%4b;>.U&RUZ5!@:T2cmّ@aFd|(϶nKaO(u2LeJߞJfѠ;Pսt _}^ܼFb ~$-z+ӪʰjOQv9p4S:1.0n`ڛ!1? !mڥ]0&$Hd~@zsŻ=F 3m nnnlOU)Aon w+' Dns;mXG1WLμb¦R5Ϩ܊񽇽 -Gh)Or ۃ蛑r/ϥ[x$?ZGQ")cꜥc B S)4_[/Hi#:cAAUBDIؾW/7A3.E(TwɟL ˣDKip{-f/B=E@*P)MȷxvI0Zv0+~W id#9 _sq?zkHsPb!gdX8iKxMStYAaE̢ӿbC#6c9 Ji~ &~rM/f7uPU1^0ou?$&UtQESlpѕe8V?Ӿۯc"+<5= G$0[Bϴor>ٛ;t\3C^>r2I&M ^˂f$W =$v^&I3>@Vgcm OAWnuyK1vB:Z3+.jC|{D Vd YR_%FםXHѾ GS˴D(40'4825[1`Bq`^}(|.a y"ZiW,?)bd DD ov8cZm*[ss.?l 2i} o5TLH>O,lUaXV$ԍ|)Ld:>tjs ALCOŌ"*P[_޻ҝ7ǪlBhA_Z9vbrX20Pqq٦[/)_l E41xQgcEAؖ QH>ṄF.@Ig'S!w$EE&faR/.;e3Hr*| C3|;Fkyݯ07?i…C8vvwPqTךmqz֝,/1٠QtB6V<_7=mJ_O.H9&S{]՜)(\^ P35;]׶(i C ]HkeoY]<2#E `c8AZ:sdԉV@QUQzFm ~n" ~3RH95kѓ:L.a]gR|kA7ؒ=:r0B/(R_X t-hfى{aLL؉N BNN 4믗jeA'O CVBu輂+&Ɲo`.NRzӆ WFW$ Qe\%&1сCev.d:ʻV!m(IaSեQ#wQˑ褏U SȽW8~n56^!SwnֻދiQ^E4DU|R@HP]ψ TF׫cKܚUKylfmѪA_6RnbKnQ&Q,6++\Y#ON\odavq H TDS7.Sxؑ4SfA,tʃԸ`m#r7sR, E挽Y*ԡe4\`њQ{';FP=]nլ"C֏PIl2@| D.j Âx0%C{hA GUL48#Fc p ELDz>nm/|q<^:_XĤtDqeyh?'q:m\S80"T!nU*FRqE cQU+Kf^$v_@?פ?]O 8cu1e}&X8T5}.+Q_Z|V[HVxZSF[Ɲsӎef~ e&4YHN̦|ѣ~ٙFgqwk_sHtF2Dfl͟.7QB f燠Sm:_Qro 7qWN|OLk@f'20o21bȵi [5o_G({d@5l+oZ|?Ohks6xҮxzuӉF5k]։{Xf^XubUj `~obo7lu~/Ț׌.Cvk]P4q?̧2~7@>:20ET*l* ~* 7'XzbkJkD ҰL¥IL{?/` rk nɭh"D /pژUɬ ^br,׶X:X(7}#j9xt)m s]P$vOQtj;.W'}ݭWC#Z1'6 eobgHM0Y;`%[͊q [)!-|e  bk+¤ը&w:x{^@Ms 7NcsAR *k~Y |5P6r(G?T. qy#2 97|꺠uq܆fY,1a!MUVW_z-+00H /.#33Q0zƶ\|1w ssG8 eoe\8 Vyp= QD:닰D4ly9.* вRAZ%$I+n=ls fٷL\;rm`s3(6M}O]D4g-0mL[mǎP߫]î-fmTiZI{\Eq>*<`ҫ_glmE]/y-$s#myͦ0P QR)Xc^MPEt/+0 ձ;4ҝhJ¤Ry&{K2y}% #U r0i">|{'1mn1tE(Y V2n'NgT HVK{Wu@8v0٘zW $ r;GظpJw J3o5|iVJ:| \B@$fk{M6FD;O@ISLW/j>"3: >Td2ߍڻ ?B1L?펁Ň#l01TG%]_ =Ba[QrT⨫[$Y͠UK+0JE7  q -1GUub>]?aIڇYWA,GfPRfnrϐrbD,=$oIp7k*bV|`, ~G 9([. vXBcb~]G´P'O R| ǪW i{Z FcLzLmX Z٥;6y) e^?t6c68|v\\ryɭ}g笅}`Z%_Oi#l]')F{;YFfb8?o F^ub9Zf| ZR&nnjW ](T>\p]Iȗ.3RAeWf*yLB$\7WI"kbp- a@?^Ҟ{1p+ .n&5]BW.=W3_1bR3> LZ#2_AP"[ %*9%27SZL!x<DǘNyMU95_I$Sd{!l=M$dWZht,nWs"5fP!ph9HpM^,Vp*#w]04KČ&51 *FaO5k;E'CU b0:>Q:J89nC|#2խUE,ABH[ㆀ9zCSA6 H":.*g|"Q2²TP"6=K<ְVt(ͽnZ0.٪ p-v:Lp%T(j E dD Ux3#+kU7#X5 ifFDPtg?!K ]Koi zy3߈ y{ X?LSVǤ{Y3gt5*pa:8ҤȥZpƧ &Qc2\_i̕2<6-sy < aG.1D(T]n&X1R||~up_w`N ژ7K,eEnRQOȲH3JP U%Ѝz(:741{3O`XZҬ6-׸Ҽ@Y"Mypv6~+ouu=K88m K'J ֋:ngl9m —01mL<=b'33f߻|_Q%%O>cg+#@~2t@ 1 ,~qp{A<ADWm.ŧ2qxc,^`3*π䱶 J64brRލ&Kzl2=t?P>B.!tS5{ŠC3g6TC_ec^':pi8 " X+UI}29\Y'i/#}pde_0n %WQ:t o F={ 84p>F*ApTBE'1P@)ƙ 8gؿ@'^ӥ komzRS _#uLr0[,*gV5ogyjLH^Եk/  xp0-RW^Ė{~܁IŪ7:b h*[ ['M`Cٹ04|YS1w5v&O^uAV,A:5p^pxA#CB7gzy-IyvfPg7#AF`uV(%n1jx\?x od63<ߴ:VfB爛DOe}B 6JWN>AO  ^X=L񑅟wjHSυɭ@ 60InE,Via_ʾ4WMm<1ܲn7eGAAQEyWeA?&nv;Ss=c-~`t'x0t]Fb=T{c!e)>&\ EOӶ8{./1Dꥅ.0qu4`Br?:23͟yGL +B͌ у?ɴ֎ e{>2~ }2q꘨|J*;X;( gdqÛ E,4?:V1 A(~֧bjE;5]|cZWaqRo =Ơ5uF'FPiw;97G> ڡФ=?tD,_Hz -2B`XC^_."PDmSZyC(4,W1flp&%&$ 2YM"Y&PP2U6@ I!5nF H}OXր?4Z9XTc10&~/5*#ۻꄕPvu!gPJN~7 Se'p}$ gv;X^5S{#~ٖ?κz@K< e#u„R%w٬}wF> 0 {uߩKk?igN%>Z9梗dI5¦ ,\R6ʅvE7{8V3 p4r R%i)ZG}u"b]s_MaC6wnyĉdcqcr6ATL wx~m̗Hu-K =PՀnl \lI8&4/*SDD85|g&] }23ъ!V]y E]=<1.@v  wspZ"YD_4T (@?4[L ~Ɣb[ĵ.> ^E9O#NOݻL҆Ά3٘ GgmV`þkOV9Y[r3Ȃus^Y:N,r:r*Uy0醑tl4W|#i&G|'WukRG%noTPן;Zcz_n7oAIFhfDz<9 ˃tM d1h9`!i#G XFN*:Ҕ$*_rHϬVh4nřOּoeTWʝkaCbNb@4Z491sߘ4UmjdhL|<.՜\3x$9Fw,MXmYH2HQd\1ތ > o=ЀI/ QP-_8Kk&eb =KĈkҺA (:UYB|zCLj7YJSjP,O0R:3OkM@ RabEbw/2vca5^*./x 3p&>s{RַC3{T8Mxz kz470>j}RiZ̀tgy^O]ݠc_=X Jr_CMsVR?)^hwN8hRR_;\yOa]/ck"[)d r"+~c`XʡMi|:YhDc̄HZpx@Yʽ=TZShTu'b\م-:S&' `\a#Y8^ ~g:e5SF`D|0d9WIѲBq*GdMI哄8 qt!@ޚB O9j(QbN$Rrڔ?ݚ޶Kh q$;ژgS֙G:Y;:@6 )&1dO,T!FG(qZ#m%1ŕSBaM?(k mN [%J^¶+ 04 ZFM]_j% 8' s-IFF q@2Irlrjt.|Ke)~.Us3x>3 ,eu3ͧcDPQBX=#L풂֘l]M/^sOZ}%54s4۫AsL]Z{2ީ[_-UoitfQ3> 0r"x*52£R4ĝl"jYvvgάxG$byԶcri+SNqrlJ{>xn ED5rdvD5ZVspAuao-^1t~*;jouw, " l"vuP`Yڻ&7c OԅQ!|iS1acQ>(P[": !APEnkqT4a!ڇ6D!iwgAXi3ڔ( Ӭn'sI Ѓ#nt}2yZutݵDçQB0(wҹOڝ2''4n;BK[â3d"u ,֮d׾~[;x2Nuy,5yi(KG#?_9HO}6O'':`اj@1O^RժG3<wA3YD4<0'?}] {!nawxrS}iPKeD1G5(W/%6I'rXm"QL<_\ƾ(ۺ,! ~_oرP9ԅ! gJf{S|tّlߤ(=xCr{\"}:uvkwKtL+2ISh!;rj5 컧^j B6qx!^L+jE#भRa??Js5{B1)90{ƴHI[j+h! p:7 pa>SIg㰬%EvȂQi)ɯY A aG*TqwR(ʁY$8F\#m|6Jo5c~e>ԃ"-}*(p&̓EkO?6FIn!A@GLɞغ{~Gm`m_u\&q:2DiͺG豏fs}t Le|俛Yjτ)/ Sp׿ucb ~`RE q(rg*uUW{k(o+mќox]}Rp{<Ä@jl;Ԩdm(i??*EXIF\>,<pd,p0 r)$0Nt4ⷂ)tsA!]ċ*(?2pr{\.iʹMw+{.Eu'JVpi.S,E y:A|Avx/E" e/-*k\?01V֕Pw+Ovmv]QK_XH;b&hȀ b1X!h$(ZΣ9I>6f6A _I{5갘])E{]&2lb(e C8!R6*+ VP­qFLsJ4x:S8VQr\BF| i)\S"Mx0 wpXeTVRQe2$ck] cĈ{z,sNuic=ovıdZ<ݥ@ hۻ'.:$ֳ#]Mg~AǟX]%Ϩ1 tIYju=9b`D[T'&z?2ѩ˷l\4hQ(|r]^g'=-߿:kgJ8n* wRe mv0-ṚN3MliYUL;Op{ƫDv?3Q626/rYH*X46L|YNŹr `qq rcZ#1$h[#:G`H|ӱ&*Q6-S-v ^' 6Y J_\"Z=)8fy ˫&2Kl7+7/Wujϫ.Cw/)3\ښxH8][o1$RˣkuOdi*' ê d5}Qv{a#33X"pvQkxi( 'eJD!kg@b 'Й|别V*+G>im)p$%jrJY}40O7E=)b.C0HqZ#C :uG[^8{f '2 ZI82<=٘MőƐݥ/7}htb2NAtBZ#Ƈ0BPQ6#8a.TĺjI$ƛkXڶ 2@30Β͖sh}/J-^ 6Ia !z0RL7e a;_I9y$^t jzofA1 K w+ Ͽ[Lf h8swf`3=9ptߧ֪ZB֋LVTlG=n?׮ f&K!s|ff$˟q˵AҭE%N8/xR>n A~op=Z.X|iAtYP+M$on'#۲gBh(|h.2/u>|ed*,J+lcKX>_~jvӌuFtC6laVPSW\W" 7&= EX~1?R,5kh=Z#[)|Q#7L` {vVN%_o*D2:+@;-"ŷFf'%@rERF[I$ޗpb-ŷY%9ȕ">^ :{9D/&3BPl%ߺV8!D³g `1&䍗s^Ij׹RT櫓aAAysً| @l1qo/Sպ.>F%}aQgN7ST3Ӷ"ҔH_*v|V$rYYr#k8يNcHGhlJQ ag -4ҰJ1* u?^BҒ;3A6?T: 7 1C7pcv8$nΛd'þ-SNVT@ ;]U1ʃiWӘgēj-;6$~Sv0%cD`Bv| $i^@4s:DQfڅ; #&XZ-Ǔ^ց)v}|/-2ß8wl[E2X&*߽ggĬZ #Pǖ%8=\@͐xY,ג[E)t5i,65Ps[6dF4Xfϭ$HIQ ,dmX3T,__LCssK\wN"fZE5h"I-G9.-k{2dF?]G"lY)L⟤-vIXZ3M 4fQTхXf>V6yHFŻv6/"ޥy-({5j{j}i՜WU %z;@h߶_ w &VbhAʣu"J! @ yGFTHv6ѻoUXH$[f6Gj[7\"3gְԃgzL7Q2/X90B3B,6|Q|oF5m7*Bhm(>LFzvfvTuvi¾Gxd=ieov6hlWPN)VKuPc>X3&POnvŴT%K?gd15:J $/RX~'/haZiF޻ bhdf nV>W|P,EA!)/οq}2*n^I )>7.+ MR.}|Xqx4o 5Ih,NRHve_GYx-rwc0Ͳrᶼ3lv6PQ14%fS0 E]t6թ9, hQ~?Ԍ}<42 ોԳB(/ 6]iv! #;fie+ŶBW_;j:,OI?4F vq Zy6W H91bc(A f-Gm$טۛfwZ^'yhux#K5M^|>|&.C:(Sѽ8zL? 间DvAo. N%Zti%wU6'1aD064[@8l KHg9 v))Kg!>81-s"xcS cAMRm1 L@ewIQx`z>v85.x" b_x"IjTv,ZwU^#:p-]tNq*{YU 5u,_sBLV(s0I^dBfFk 0䎪HqQJߝ)~ޟdzm!WӸ+mq5Tn?ZxYЛ <^{?VXh\u+R3Ye lw^5Q?L"U䅈~H"vա|[ | ?)F.6sw"MN33 8/,.^Xwj_ t_ZKQE0y0ҍHMXG=QG}hKs'a>195| s仔lOu@ 6к6R=6XJHŨPҲ(ϽAaR?ɵ ;CL hv!gq_o~B2nZZ_YHSKJªR[,-FK/[VDCO`vpMC/0, ^W|}Kq[hF 3'N2 ٩>A4DP^읍cGv)_[^\vM͑% &c[Pndܶ7콌r,lJv,ʀM=4Q߮{-޼Jwnw9(l2#*)l4Ei}[dSe"S~V-1W+i9e^ ٠H~G(54^ pq@KD:<۸_f7)lo:K ÝI4u16Šn0[ ekB#qA L *by8GE_!*Wy7"V7<.QH.n+5Vr$z="_//|-5:\p =揆'"Ge{ǩ܄dW:jU@q;Xق 'z#)#uXYF]+8|3'R+hx "gץtC+9Tݳłb(@>mnź]ł#JXDKy? Кz7$ƏA\A㸎TΨ,';ԋؒ眼d7{4zd<^Ȓ+#AXz0 bEC@iRpr$}jgM\vJ>5䳤#%Z}C~v&o[ee$*.\5݂Dȋ֒WfCJ3rn/4ξ/~@u,=.{0O4[~t73r9vۼx?N *(_60ě?}w-_18@.|>7φܳP#2~Xi#(Y!ڸ>DL`=KN 1/Q",ke©x+tq!ksG@ h]Fe 0$iq}o~5Q աT~?ZwJJ8pp$lyښ |&V]Ypם3 #FʩKCG"Ohzh?Ic}VꅑɓlґhEkuiqI|r]Xrsov"eTo}Fg})t t` 2JҊ]!?#$rhلv/_ C-`4jmNvo0DK\6@f1 yfLBr0jXa%U`[*G;s?SI k;ZӾfc5RP`V0?YίX,c[.²Bbd_%ir&=1,Z XG]K#-8+e%7pϯ O$YkvLj 7Tց\.3Z8G)K萂`K)NHuU'HJrlalZ$)8W.DZ}G^]Fxo_jB#˺83)KO[ p|P\^j#}g޹J8.տK~uP6U.Bheirkư.RTS3^>;~j99Zp{0-S:ڙ?6:>؃BYLwLS5Vdd7YB#s+w 䌼bQS d.(Zv(Dȉ3#HGOP$Xb2>yhd%6*1ծ0x ~S6dy4[ iپ?ca]1Wӹ0H7T;ƞaVA"7 REG%.L=TLu2if{Jt WQ'D{10MfUfx+/l}9cXvhg=/[y~\)+ Z#?2(+jl4b211K{" p5^tH-IEyKp$iELٯeQlB80[GRaD*FGRUzFȰUp b:+S\[xUn"r 3&?fX<Q1R8[9-rk,3\G0Fz-ӫ8ɚ>?cHE T,+sL(+ mg&dl/SJgAmq]8qP/UESGCPpSQJ\o^XZDuo3$nrqE+r(;rؒWl臜۽7ER_!/La흓A|mPm0dr;r1SK&0ۦsLcɘ5vO$}uZFEH,Mrfz3 OޡXŮ9~hIP6}/&5.&֘*#bn\ 2Umˢf`aK̈́`$IK Z?a:$@Zn(uC}#i "Bq,2!yųmQ e.̮b9ǀ_5 bd?:PUńbcW)9,K$?XV_H?U3FZckzB*=9ugi:Qs='fqOTaX4Dz\ǎ[EylA#vR ˃]'3Oȃnhu^<U85 Ciռ 6 Dv $AE{vᣇ1'7 ː(5>ՂJx 2*_IW7[]̂DyhUc`l^a:,B(1`~ֱGbh緼( .DEQW)&>h#@Cn=!iZ܉r(aC|@ƽdvʖ$Aah皨U+GbcL*j6ltgMܑEá%M /eI%<ɲ=o }7`U&}.d(zqq;^zip=`"SK1/B^fvJjqd-Xmu>IٵYEiyĖ?e0p jOf9DŽܽ^xb̃YTǙ!V"!. 2PqxY#\e\Z_#6(+wع _@ ͆pN<s*FLMJUJ}(r,ISҍ[2k1b ] ~YUqIIU%Mj?Rv7֟T Pe%mt!/>z&VS6f^q?@N =ܯMH IkS#^h*0~q w7RUۢyUTA$&,3\RH`Ov͵$ sɯSZ-)[E0c)}+N0?-hnZ\qvgEOuOyo꣸TN*z' , $tEUK%k 8l 7 eS_`L.`O 4eSA z2]%8WNчt ýC䞲Dk/D#KΧ烓إnST!AWO1SyZ!a7 <¶?糉l^%hW08]j:Ɇwti N(|:({7w٩%F|Ӫ$@)zLȊz}–03 d+BcuNvp(:ETJZBX9)Nu<{ztQG&S=~|0ɴiގ:.H&w3fdMAzmAJ*aş_:Y ղFy$Q0g@Tw]@00x _MMv,{8t s+X{68Dsg&>T3'_aQnFZWL͙v(hn# qUkH-: Sm%qm*\ w4Su]*.TmSN︷=?)16‡LXfף9d3ֱ./%NPcZKeʟemݩsrA5 3BZL[2EgR%$ybo'ks|=}W+{}ƷhWSߢZ<p%FZMI+3͛r3yTڳY._qQ=Tv7(C.rȼƻn'Lm.1_E`Ofs%qjm<ƱUPM=f͞`)x $sރ ~؜R3ΓؚCF|]K act.e&GGŹBfW@ff4n֧HQ>TfVa=gW~8 91b+6K.Y^aa0fBӭpWP4M摱ݔPa7n׉驎H$;֗4rs5jj\J 5U+w/6@xE&39}⽢@׻H4+YEi6iXw bli[4t,_9臖?9N+^S~c <c-rː2$Z%q*#{xj5C޷/GsZJN:Au Ⱥu&`Rg^y.~ջt#ÕǮTA u|rGV)<6iଙfTXEps1woJ `l>. u_$7& H8nBsR Nӌ3 c0ɽ *ѕޮ_R CIQAiFL_*ǩAT3ą>ie'\{A}Myۀ{C h}-^+>ԟҕ0Ъ %ӼZtcScf^q*,Tw΅~-b%.!P_ 3#kޚ32f"H3iE0/NY|yir[ĵKgpսv -FS InM*iUc :9_[>VRVmkW/9%Sƫ;yf F4n$NeeUŭ8(<2:_-G -DiiQf.dl?r=|usO5Χњ3S1B.IV:McM=ο4ENl 0UħyD4SKT18yO{6ۢ>Y8^u#- o<򵁩Pek3q\Z<dP@[1#:Bx|ww7-U 9S`%J!xuџs\Hעޱ7Vcb(*M#!E48M:Vr{o/󁤏y5vg6ў&&MRUoaSiĵbCkɒl;+t~:sP6KSq7o"ij(c.S wtG6 xҜIxIs@OK%{VlZ nHqζ;x.;^JQXح Oh4u#賢vw\PJnA‚XO:7;XziKř"Vď}n` ׼4Ib}(Œ 4d g) ]1У+t<֩͘;@lCA;I'Yrp "uQjîMXklol0:V|VJG%*,J;\O> ;VK:bT思:z+ R!Lo*`x%w0#ܢdM-=b_ UФ7$Ʌ<͛cм_Mp*a-/C$ÉMD&OMY:I={Q #xznnk\9Lu^v`sƽhUGw y"'3dD}8.6qrW_ɶPFfITn?6),̒';_zK"7`>4x9H )|\}QЖK.FNyH(mdowՆF?Y:$DilvD5x,2BѣkdrH5ѥyn9(] {Bd(uR{V:_Dj?.CfZ : r(9%'*bgJ뫘%̟dg]I\Irp5Sig ac2ugxѴ5ݑc>13\{c?DM: `au㋔vԝ42YkQ0^z*^ ޏ%`΄!rb\5*_1)/S,mxM jv[OVz[r61l~@N(5Rw&(\Gj6)Nk   bše غ!Y%K>KF/oHջe@ &~8FElmW,gtlDսZlO.sk+Gef9#ͱ9\;̧GFAIsաE4 }ރ J,kDOP'f UwSC*IV`9`\u_t7qJAVQow6^Y7}M )`͏+9Kk~W{D^PH֣ΘgjKU@;q l30rtkFWo%^@c2Tv]XFn= VRa:;YWN>V) 7BK(ry$ <8E?A?J_AU~u?ko514.tʁ}^?_j ~A$3Ȕƛ8d}$.t@t`@l*xEb=4hJtb _pdm] m U [~jMgTZ 63XS3MF XTv]MǓ4SIgSfTVy d[~N> 렲hk@@~g>܁*[.Y'?;oO,59Q.8 -X,.ne `l׻^@q~B[DR gR۹ai^a {`Aظ3ťj2ڮT,g-VBĥ\N[GuF]>ASfs]JfSwy7 To , g a.ox*:GC:MG8[8pAo 8QhFEj.0[FʻǼ1%Q4K=ꧯd_z߯ ^k.H#~qH  #|f&JkW,ix?gQMS6nai1W"'F@B%;!/ f{@M̜m6QT11>9H \|. (Ǽi4 x2UKCF,5bPK0yU~ [$q ߴ C ӾeD|K3)>QS0PWژM2FU6fu )` +qMsد.Mj{DJD8z!‘ L#z:ꨙ_Zxesu{]|1. )}Oj8kEɄu }'b\o懔j-n(vev@* @բi3CBhYiw#yU UW ty}3߈zW4'-֓+jevP 6o%cGSVݨZmN<8#ykSKd({NVΐ.i>D[WC%WAdㄛn,l.A|18#|%f&1fZVl=Iw0Tw\v||P19/F@ 8 苮)Rv:I=NV M<$+$;?@檓sxb(u( V0̩£פ:]1SS}n]s78)rӦNBž^_j6>@knwaü@qQ||?1s&Sq!SOoN3~^zAVr8QVkRFt"R;59z@=dhBuפI@xDٞ0U g)Y⮘ uH4UYjYj e-2dr?JnG]WLa7D+ XtO}l5%d[}^­>**ﲍ@+{tJf)&hSܓpnY[{S|߁Xš+P/M sE3U6{O:#x=VZQk5'zbɻuR!^8/|`7!S :5Ao1yJ4RE#,<qG6pǷYP$C;7tj m_W^$thmSɏ&q#`' tZET`ᓩ{VT/+Ȧ$5[p]hW-|4ѥ$"ִ!v"I ij*y]Q_vi~+g!6ZB㕱&+.P 9aݬw 2",sVC0gGHiͻmpqQq; א#ZbO9V1CPn9&jAjM3(%aIGVDCg}z+q>olK1=}4 CbC9&={V@ν=wW18r-}rf:{ws>̗1@ JSL~hra^*YҺ|;2I*Ϻ6bG~,5Vz.?Rȧn9 "-);lx]@~~Bn C%7_稣ʘ?kql8*`;;*b31ae- K~cXA+B3r5zBΏG`¡k-"pZƄ0+aa66qEe3 PӢn~U*sD/  E.յYVVae&l.`UhA ]M8aMGXjߨ|1Rl"=٘|ә4dGʽ K@Y!yCa&&K_1&̹<?sbOm~1Tim SCZFg2 '& hõn*%I 6 Rًۖ YjZ4(+ FX[ڤ" 8eRj;8r zA+ޖ3afƒj 9[w o#<&MCj_ A/ymW@G"j݀ԟ XF5ȒNvGVAD*sN@ }bg21 \v+&+W"h9DQX⋥~^KErS!s1=~ .Vܮ-]`.@#;leXߤ/DDH=,zs+x]"g:n7+ȵ!ɯ_{=m3*D:=XzpF#Ym _9 U-h^Xl/Up~ę̤ xJpO:DH :DI-)|Yx#痣l.j#Hd﬋'.XVf|uQWx2\*ܰC#(px~t{N8}KP9ۍ/?Wxgcߙz|Ji)}$Mk2%&? >h!#H]jWAVy͖#FL nb ȇhlǍlJѻ83R nN\&irqmu1}‰ _HL+J1g8T5i E.8z/P5eK'd,㩔GĎs\/ !J ^D7PQ{ c9u~hsvhNYOn]sWCn6|A9F4(2@B-a?({tCK? HkH"zp`l[3V,NHhC`ghppޚpGx}mBP(映q_-;ltCV q'~a|OI `<ז`'xq^m9]ڼ5uFvԅ~ IBa2!O|"GݱScaj .ṱ" ۊj*ʱr@wj6B'vܼӰx.(%zLt%h{7⋱4w^) l2LGɯ!ؽD`3dk!9lɤV5ѱܭo``dC,S}YՂ,GIZ?#QY}PǝZ(Ctn[8aO|;' ^8ƊRlN3ZhScfWw-FPoe{7w)/#7t:#HJ66!؃]ɬx.Y'N!~gY>F ->YHSH D[z_oXV#u_K1kŃA\klW+w֐R:%BҸ~"9Z` Q]??M*?{~LG2_O#5~{A#Y*Ku% nwb-?l {3u=E7S n}>q!ԒrT%;Z~4$Mp`?8)󇳓u;U&)6g)~*e.@Bi/u O0zz ,t n{u.RiSo<4}te}=MJ2=)|*EcQ-{ 6`cj^;51ɪ/:;FxQ*sOrX @5ow@)NV#j=mn_p~98V@8G u/7}Z?)ֿ`3K_^Mle "0.Z#:tW>O8C 0|# 8(pmp:!ڡWI~VlYt=8&wg8z<2]2k(H}<ˆ8Ӟz09!cv^ %Oׁ @~KeBjzL:MC=~~|3Ag3ɰ;Ǒd~A?/ϨnOi|H;D΁Z]0 7Tz@w)zg`GW~R˃/NSidd.+! ڈ`6N p d^cͧ=ľ4儲1×|ߜK~DEŰ)Ǜl9b:oΟ}+7ޏM $Uyc؟H瓐Fh?'\[PN@H?lpٵql^M"f.;@K`_yDpoJ p!(HC':~߽ O]x'EiNn:rd SBBnySy*decL%S) v|YAZ<jB:\CZCs9ȇ5?ӯ)DlD36nAn]p$ *o7pò 5AuZ[{#7a!gT;o4GAWzN0QɅ\"!1)}XP z*EoSktvA F,W3UNk␡8; 1³~մ= .j V:7MV />nP<|Ź%spQs ƌ4$P+40 O1ve"otR~|߻ьH!UA @u^W la1Ypr`b]رlp uIP5NLzt;,!a}5FLjc9:tTJ,7aCB4 O*@>Ң] !B^2,X5vP#( O_c@MHF_6Kad/f6J[-ˆ/&Grĭ=uF_Pq % ծAL %Ҷe]DsV6G}$گI_C]lv% n5&p: !\76^cq1 EUxor?<2*%襐i~.Я3y92,懶|l RޒR hRnf7͈k4K3.N\5bo3o#Y5` <{PIɑ%t SKGW 7֠t^о)[†z3 [hRYuƑOz&0զ!x#Z5˰|}[.hw:9sD~#+ϰ9R-J݅ؠnP[+hq">OYv}8JiB k'R. u8whl fR=9i<~1FB:jbPCFo2OXi>_۲UN$v8~|Zw=s]^,.iiK(8̙}E"C ;qoVj3 =E-XLS4YOn9hP%+N۠G+?e7ށk b!զh{:~6ܚ*%{o% /3"h9+|3aZh+OI"c qH ҰkiNΔS8Z!n<9"<ؼut @a88~ ^ H 18!ɘ 1CڃKlg/ɽ-T9͋y9wX˧*?Xʩjqs810en 3͕n$eg i9k@!L6h><edc/3r;<\r֧zB٘} fp228H5[6, /2IF^FV߆ 3f2Mӌ&Js4IE>W\c]LU<,'XD\jy }؂U;-s~!FRB'=[)@N*4?R4UryFlv? fne@xHjX7ts骼۰ ;ywN1vA*'דEV;UI> E.94 Զu5A#_bt|e᤯|tW@o3y ?P~"[U(v%(":d!%55&maCUI2c&&^{?R[8}K DvCRnϑ"Bm奻>z*F3K¹GBb߄/nB~ܒ[i^ 52`+," 3R(%ϞiB8p|۵w‚lD9|VoTb6KS5!7܌4x &3m̋a*|&m;#M/"ǯ#r(! 5UC_BEŊN6OهbZ|b:ʯ)!{㶒6Ӹi=SOP5;zʁ۫q 5.wJN|# 勾d%k bh'wsf@kl=q,diHh #ykε2qv{ 4-[0*t)2dSMl~ѥ?'p#P9DT}2qEG/KOcS2EZ׉s,uǡL/Kik W䠝s[tq<:lJ$8<7c b RNtdVc${+L{7%ͼV'6_}1W=24~: cGi8`KfV+9zk[%|})Yl{s *! SH 0k@In jܵ%ޝG;oi.i ljWސfq2uبd?LqE튾ko̓$fIҤ.N - RhRɃbT9jGq6IA/ضO9,0iFK?m9+d Y7{uy#OH48F"ѵ,}¼M)jN|/KbhGXDDiГA@x^Vi$E'Q`.^;)?j]"UZ HXbx[Z1gW(XNmt 2؇{$ֆ}Jqٞ:K]8Lz|EXrA) 7eOM8 NG)|V԰}ʟE~ u9Guu jGOY~aOԄXnG.΂vî/Z_qmǎY~] >XZ`Q}:7Ƞ=u5X)>B=w|-08=Aziju~@]m9#ActA_FuFM-ƄZ}?Ȥfw݊U҃?l-Yf6+1S»?:Oz@'pa[E--V5ǝ(!'pڑE gﭦ;d"^Xˣ/)u׶-J=a""5vk=rijP 'n[~5D[LOc4~>tmj(o GQn5 <調MW&׏HwWdp~я&2fq{y+A]]Jɔ*ZAF#Ȗ?~X59\7QDa"ʑ/Z&J寍bKch>͇?3bG/μەoyu zSـ.ǰpkָ@IJxԳSGܖfMHFc 2]l6QlքgVnMi1ZG ~zzY@~Șo;Z]aR_`,@$]VC{ErlFEߐ~tm2o*/ݱ~j[~EqhѬ !gb aY/jA}y^:r'zU݂jmOوOg@YIܛꉸ i 2X4*)KN #֮M:쏳a_hr>~nJŸ<.YOAѫK_uMPOS)SmH "ZX 9~a ;ɗi^+H4#@5kE}ФzV5pс} ?ocv orpWW307CNX1zծINW-G49e420 =j~;ͅQ}_Z7` LA5jFwntB‹UUey.|jN/B;r4yDNсb&NYfa8x5fYd3%H-1O^LKð}~FYh,1 '+i}X*RsCkG`E?i\˲(@ $ |ߔ-CUgFAHߋ%|6%;)1xM(4QV96! Uy/{Dh5WKJ"°NGU\бdۉ$ :uTvittSh%g;|'1X98/0pfLC#BS9"L>in& T JFwm\wL/pFfKT(]s}+|_~a\8@yyDhi~ɧ(!z ss䏞9u@NȨJiD-n,μ ~3SlN/#|"StÎc>sn´hg L@Wk4qw7vP杅32/S!ʻ\]xA}I#hKYW{!#phh5Ol&>z66d _/0. mqjEюZvkYwmRz8>3BGmoί"fĶ_f 24 ֊^oq'ˌ݆' w^p?ae"+: od &ᤃ-řc:6}mj#aDX 2ܕq8JX=h'7j[] %d_Pwh ` 5_ Lu4]~ ʼn qfph—頒f,/(bAhm7Q* V>CE# ZO-1>T@w KA<=WR" ODK.ɯ }L'*VFP\y#aA[64>2FBr | aMPj^B/m.;eKaN_Θ4>CͿiT>s.6 .Y9}I~2SVHQmC^Zp9}ҏQ]5+`|vN1c(4x8ʙ %S_(wlu+ 7734 Q]FfB6g({?~^jq9/Y& HuTll{6rx,@`=N(BA؝.@MfxĚ:Ti[׿^m͡8A5eٿ߆鈾!ь\dNFtc~CqxO o9/o*O=BFǪJ/M? U+lz.;J ZAv;]S5%Qm?N uAiG9Tn32h dw 9/D4TRQgs }n!iVRX9?Gˈt5f=5DhnM$ Wo<LOsD,GCpMF7 Um a_l r7دd W#b/ p@,b8v^|]]&[&?#κɁY*nE !4c̼>5?2{S9F -*ٲJ$G /Koy4XƷZǜ[҉"e KP}UUv~&W;ܟ;Cד 7V:vtq]iBJНinʜ1 <=FAƾ TbLǭ-Y' O Iʮ뙾8jx@HD*ث1M֨♔6S'OPl_7+'޺?|Ν',WUrU'ޔoi'e)Pmj݋SW_:g|,?ak_^]lRIn јWgA0l'?+,ϰ2^+{_l2ZQġu_;58U7v=' <'(DdCkOGn.OUh.K %ó("oMRv}XGy֧PA\)+CС23i까]֛|&DDFK(귆pLY&Cˆ,ȔڝGᕂ0xdŰ q :~ JSszL?6<.8_[T*`qDӗ-G-Zٻjgg8B]$Up`5E7UD G5i.'Vuo0B=ӷq̅!?@c\IG򏺦׿4}͈Q^4W4ʚjDn-Vȃlx5HX!nnr< `e~6ޝ׺Kِ2Wm:yYHPU_ފz9hbW-dى'm™Y{| ,11iiQ@IX-!U:jQɱ+W9X O'5bf9c;i`@b#3(yo%#ϗ^#L16S9 S\HRb' P/49G3B⑙F98YIE'/#)ŋkn/Hꧨ{d?Ku:g=nj,g]x/ĽUr.ם[ ^V83t RL~(meԳYwd?{Eu~u1ʌBzFyZ56:t.b# AU"-݄ >'S,.4I_ Ru@ 6ooa LWS[Ԗ\S_lm6Dlm7z}+}?@؋;Y !I&PV;(ڦ"v(PРN՚ Z>hk1ӷR WF?fZI3 ֓{ِ\?NțE NTdm(K6*ߥRxDz_<7f 0~ỂAQ&k`hG㙸Z C7MG a(oo`YKyܐVkc5s/p\ Ęjkq{m~ n=9zU~X,֒B=h1NUQc!#'8r$JATsxn6ꑂVF{ܦ'?[%X"H;:[ lqn4YQe_N<ŜTs{ZuHM tA7\@a=jQ1Z_R/@`^2g1u.7,?XÄ$]9mP9+xL‹_؉:nNz A, }TAM+Vj@{V4R]k\˻ኺY_=V_aГs :\3η9i]Llڄ*^m =Cl-PH.6oo>Z&Zc]Wz #&%Pp/E)ӰC*h<;k1Ms7TzB`WE0O$]}}*$qoX$Bq])_<֝kԮ_00!Jy;_%؏t Rt)X__ SJdEvl~> aG"K})u9iuD3f)|eUHk)+($ `|GkFqlrbG |_ˎ td-~YmJ*\1} 0_6W?F6x%(2?yib"edO/UG LC^~OQ4xt.z9 2,gvث.%uҰ2@pkϜpWXx%/9@ 팒7ɲ9bvE$xJ޲A`_+db@Bz6P9]8!h;tPKM[aR] KL2" 8#66n?⸃X)A #Jyb nơh{U+h Pn@w~K-Th~ Kk>_T=Ԙ8aԏ mS&(  1'&ͼHfeESF]k\'3xu7c ︮B gn1@<MtZcTϪqefHQM{xtP(bQWQBbTejXJf,$~Wwgm 4\6,v59h̦+"%@!f hFk+{Û6V["f [3v<>nP':H 64l~ Ke%Mpq".+sW] e8PlA4ZK@*̞ymd:`?pZoW;[+(%:.La|wϋ ^Z ;WR˩_5_;YP@叕Fxݖwx&ø?S&8Ųw݅Ӻ8"MBR| >Y-L ϋ[4t"s ߆׆ތ;oCz*vdL-Kڟgq Qyka4jk/.`Δ>zn.ב<>\TB gcڼ%J#"?Иyt [^f=^ MO9#y`O@0> u+βVX核 `<c7ܳ} @Ԁ"Xع,6q8v6hXGQ lc ٫W+S[&b`]Oðe)n~)EW_|؈J&ql&mrxy U W䙢u\'c BjGyZm:ry~y>!̻3Qiߒ Ԛ-P焟,PpIodEh:zꮎ/&R.@N$ANϛWN1Cڀ//W ۭmDN5pfTXn>7'V4`l Iod_u!0Q5@K9ң/#cg*(\GWC'$|s0PC#Jԡ,nې 6;%)Ͳ;s&!EEZ ?MƠ: NRl  :(8Ξ39Ș@ jjjc,Z`Vq EܟJ' AIKbYީZ6|}q\LZRq q)o;OJ_@z.a|liwgeAvF 3BAaU֑M dWWeVXQHHm'Aswx6!] B(u`J2|X2-WLU} {S/^I26$a;o +{YՠS/g^,\n,=0=ۚZwݶ<-Z$|4A鮳b]cSCb Xk`V)%]ad!]-6tįGl %9TRpbS?*xg`+m,;C c+n5 +D!+hHO6nZH#4XQ1.I/&17ܶЪgO="zI}6hETjgxavqalo*"s89Rxg*?b 3/x8Ce̘ǧ'?48H>gX`!:io&QG4\|`zh/V!,oK9o=N?ڂ`9?ǃg榒qxT?ߓ ?i@m* _-2EJʦ.kAas}%J&wVIEֵ&g×(T,ً>^&'`lK繞&b~#o/vynbŦ82(TDݡ}5UQjA3ٴj.^3jwsjQ{!;||iL/S Wf&k,bO.IYa,pD$ؐe5m3LWUvJfpU[`V,!-_ZBI^TF(w[@>;28="bIF֭*GA3|X=q{|ywƪp91l1$V;1{8q@S2\R`+7Y|c[:(g>$˼D -"1i"Gv*%q֛d.{+t H؋;䙅2X<5PV'uj|es*u~ z#nn*@QjĨ2hd Uj;:C=*طZ$jY2GHfP[z r}dǝgMY~JSY}!8,;iP+'w܉B^{O?oFh-Wh=oȥL8ՓlـiyG+D4-nz,j瑽Cjxt-JŤlTY)\Mp|i]e`'G#[i sfDoMV['خm #ò2XXwC\D 6GA!'@UuykL3iaPt5>Z`MiHkBwSR9(^U!% boM#Ou7[dKGdH)9eGqB&.eU"s>ʽdܹT;Cg\^~ lѬm+<|KQ&z`&e)k^>bOt}R8!5hZ$ NZkE7zF ψ3|D xo}l.Z^pd3|d4 \V/Kdr>PPll3V7P5S$WXe+Y63XJ*S I:Bȝ_Wja7xj|˳BH,FqS}8{vyEdH_. eGaE#N3W8wOXosmsmlEi rylI52zݓ2=QGє]ӏ+}O+7 ^d!´r~LX° EuJl_n=kC gNjR8!5!1y4V-ٳ.l\|dPcZ5q9d#$r3+ 26D2q䣴EՒEIr$2IO_nkS?;AA_6Ӕ556x+Цf.ػtN{|\Bf`ltxqc~IHdQ eV^fDZ D?\-0PlQ_gFX5Dۺj5NAn~=xEg&Ye})E.~V7Qx?J)ƇY'U~ 6GkZmtBϺ[g}N|1ϵdI` r}*# A<hf-#U ag 74 `(%,(:HOa\EMmx/B^ /m0`^¯дI oEp厫 'kEd&`$.?:"9Z론 \N^g'1[o 9 #hx&CќR<ʘj3)#A6 r,+:8H6Un>F?bGja]l"J=@wcωTaAF``rZHYETNWykڬZ.Yb2Nk3;;Zv«=c?1aL%ӎ3~xOfYY܏oTH\E)/u3aP Fڮ{^=Nր+%dUPɹ-"(eYեq*3t׉'v12q+Ȯ#ιŇ ;mǜl I$Nr%Ȱ?bvBoo泟H`$q\*!$}Xoߗ%E iINm8VJ.䋂ރ h,XEg뷨;ETf>2iz3kϢ0hLثgMF~RU)=j݊Iׇ+yeΕ6'р#w XRbg ,LaxG` 3-iFդ~yTP7X/bUVMj>PTk㑺g8&-~`+h0^/ t-#AlP񺤷"xQ< PoK ȝyBm If _Ε(pM<4XWDzHwV xceܗQk,6k9 "Pnd a V݌.;)" -P81`o]ɓ?,,H.ev]|js:2ILPjIg#Je'y8z.A.mm!Ƒ 2V HOƤ·B.]ppijR%,K'՚rcqd0PxUp/H]I#w+ sChBG|o/ }KԄ;Qv l Fd']3L<5J:h)^E:6ݻc-<4Q*iw{ ?.Ƣ>y(q,nxY#nDp(6u\zC!QbSqIWN`$_>vqo7vDVRHU';ևqP&ld !(mΞl(.y]qvLS&M*TM80}xCYуR򮠤$&mz~}6j%~Uِ͂Fr'bƠO'1C#1!wWR&xDnGl[I ~@=%bvzAMo YLK]()|iRaB.&00KY)@2:lI#M t~ - jP"?C%\`D<٧L)#,T'\H2I|~ *7Ds92o۔tgvPןgh|g`> crRŹJh>R'p=N1df \EP#+%D7["\p#Cvכ<ЃIdmBEe=*)`= #0@RȵBs{ 8Q]ZmlV:f"U[cX!<5ㅉC*#Zs33HʇLXsCc D|y5ڥs{ash~:eҗe窂"LK•pv2L;1|_*$R{ܙϙV^ T8N!f1p!sp{ 탠!#dR.} ws0 8>-\VCʉ +K14@S}m:lPXރ`Iܦ:nYPDZlQep@U聳'^ojВП<NvXZ>7'O,9V‚ī)Mov*J J.3{a$k2r[Btx`wҜ,FSJUP"VV9JWhLCf&L#4⸦X$,=$mҔ.a8ovh?mJ̜ ]F-!P*]nNzP7; A3{@A:--6V24ED } ´Dm~y_|Aeb6U!rH3}$Aa;?|?L69RCA0Ц;4ǽA¹pw3ėClmyVm,`I=:/z>!3T2Mv`Fߨ!͢,*;Ce733pӖ_@So&vc꒔%Kv[y1i bĖ45TkG/޽#;YyvG/[dB{1>e/8FJDoG&hӑ3v:\Z+FQ/:q t[ӅB;`a! C5RhdqGM'+VEBB  !ƚ_,?%۸Ɣ\r3Dj۠CI4q~3iܤGK@U侄1 HQe[~pR޶ۻ|m[rZJEZ|{P9$Sp[Xg8dE۱}yMw?_3ry0Y)ш"M],ѲuIƞ%& 1U10S8#ߝ2ᵂTعbPw%t˘jZ)iy>qWRn s2t\VdT~ch@i&"2 ixt˞'Md4]0*sf@26WvDxd؎Z Ch|R2uQƎZQ ~c)Փj.5U<8>Ţ@n,Js -¶ji0 niO{KS8M}B5Iup+Pj##}{G0yvLfV.vHw6=`e-=֢@k;'vف׉gou&މ`S[kKdaXǗy[@LҐπ+gU No_)dDz'֘3?sk3'[ci1RB|?(=рu%b+/BaSһ4;(i}7ϸ1'?rd$ΨkXJj,>H[@O=Tڗh u#L6_|H3p GAo] nJ(z1X|L]ONUr,w9: Xv"XÐܝs󒜕 t- ?l0`<{ЯK8FY]tSKOH@zvIVօ^;\.dA1`r-5kL9xrb|<b >AIwHX)k2Qh}.K}Qm-ΚjqWb#!3/kNvx!W|B61CR]4S'_p>CDmI5bA%N: 6޻^YUp{ hU:F@` qi1+njf[fj눌 yTJ*N3d.KsIEek@YU:~l9Ct+rs'FNJlwjBf #i{gP5d<ؒ2VzȜienO#:Pi0o#g(n8T$ݍɓ7Eu3i"$5qǺ; z瞂qcMݽy|<έ!Ґ`dnf[7КS}@RNl)IV^|sv@"*K}Y!Gs#~W05vJnCꖦuv3Gk\!JTNԫm'߰u\aٯɆCgiXzc,$rKiL?`Re_a#T2K9PA\n`KC)$E.?Ű*Πq]Wl/A`oI@51v߮ Ajfyq5na2·Sb\[I"j?@FS=%3%TMɞ4ѐH9“q9Pd u 4w ګSB; 3hͣvkbd22.w{yP~PU~. @8ۯUN]3mD}&gf˦*Xqw17I{]7۠EҀ0O#Ah4/wuLlW# _jpSO{UsFQ^ـ)aJA4Ns|?$,ؾ>.h7k6LfpGY@ [=:OIV9̥G)nBV4{jlPP/lh"bhPX7mMf v}H& j;!=̫RΉȁ=y/&GJ @Hg6ewL0&/-.Ht%6vBHl&3'.ҕk8Zx]f`v83rx8Qloȓep>Y.ڤԗxx'QwN2_E*0'v3~ω,vŭuA }KHR=u1G)HQk & ?H#m囹w6՗Jsk\,VnFknOW}Qؙk>anya 9)Qk]G!sc|:O̢~~߷GWQ0bL]v>0+vrwB )C0~罒>+>0.NRp]Nј2ꜢvIZ@祍5 Nܕ1pryGt.e<1z 5U ƏM {0t曤ק8SH/'T~\X{\C|cħ+R~^/q##Euh-U(:,Ejav"ҖBaR!N!|14/>jO[Z8U̟fSi,4Qf @1j'h1y[uP%-|}Q v,٤jLl`-ELF3iS16iUI BuuF>䶟x$4po*Wh+^!6f4)-U ż:_<$ef{ptAu#GqH wRYa!ưyCM;ڰeE7u ;u6vc;R[R}tC>5-8dܲe# 3%،PSn(>*er0ϫJSkM8i岙n5]Hz_Rdn٦_\9})˽tJ EtR|vkj(IMj;}d={Ea"Km]NUh "P"iqt(;^aKMm[4GSkT*[K0j+0 PlMǚaUHJˠd9%?tnP+jAY6D_B-j55J,vGY*7P8f杚%T=!c Sx|xZUOĕS7'ta1yxPUiM?'\A<g >ns^dPyV=\$>OL%qƠ^iAa#wAYY ުg )؊n7T!Re+ѵu {GSY.d LJ@AV?ϱ gP\˭)h۱E3^bZkcE:nB}j? -wcs%eD(K4Xr(Z`7^ s}{k$q;3ŗ$!۬(.8u: l)Rƈ$"!|TQG&2ƓiT#fU}ڳFA')܂/o<#;SG:|֋J-j`{N54 Ya#Ъ8`k05W;{%Gλsu"tAi[{`)EӤ/Cf4ωbBF'dj_LUc8R8+nA:.c*=>/>LPUSv2uZe i; ZgםeՏFʀ$1`mb=}y.AE#0wd ^3" δ3JٙV߫o^^jkˁp)+ w"P{ Wp`ZwmKHj;`i[*Ep:J[gL^;5 ?Za|)"L6Ȁ60UD6ծsHI"`~M\bߴ BʁU6L8۴ mzNSbKhæ|А ?ԑ٨.aop$Dо TLW^%5E^x|8٤hRC@gS;J];a +TgH{M1Sj G`Dß9 "*m_E5 M+ ,OR/ņ9vr. ( |\L^nYZ؂cPMS[+2{CUѤ`MA ]Y ˢ..,U=2Hp7ճ܏K"LU5iLDrfjJB0~;l( OHYQa򘞴_Ʃ)yBEy/Q0jl_/|2s;azR ͨFF7xUIJ~xW#;|#xY}aUWFKSZT!C@+dwlKWa)̀+^EK/I>ceZ26k _`&q݋a7x΄9DwM({RI};Fd$ٺ2E՜#!BK?)+r1.Y*;.r Po Imu*WN.pYQ:ܮrfM uQ֛j.T0Zd8/bpo{x֊udMO-vJ] p=1t|"$fL\@@S-ThKQǗjr{X Pt!;sL"b T<|qI,ՙIz 1G;+ۂ٦0>l zD{Xmv'cYlC=RJxEŔ˧ڥt1Im*RM]#Cp`k ctQjse0ֱf^ԉW~ZQ{%*{ŨcV'#1`XWbg2h7.pS_z9uK t6=Ƞ*&J4Bϛ V3t: uA:帹5n7vU@0cC?,^}qgg~~ NH̬ A:?^B,^xuo3+f;0YZ