motion-yapper 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +6 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +63 -0
- data/README.md +16 -0
- data/Rakefile +20 -0
- data/app/app_delegate.rb +5 -0
- data/lib/yapper.rb +30 -0
- data/lib/yapper/attachment.rb +48 -0
- data/lib/yapper/bson.rb +20 -0
- data/lib/yapper/config.rb +18 -0
- data/lib/yapper/db.rb +151 -0
- data/lib/yapper/document.rb +54 -0
- data/lib/yapper/document/attachment.rb +26 -0
- data/lib/yapper/document/callbacks.rb +86 -0
- data/lib/yapper/document/persistance.rb +171 -0
- data/lib/yapper/document/relation.rb +84 -0
- data/lib/yapper/document/selection.rb +100 -0
- data/lib/yapper/extensions.rb +80 -0
- data/lib/yapper/log.rb +5 -0
- data/lib/yapper/sync.rb +134 -0
- data/lib/yapper/sync/data.rb +12 -0
- data/lib/yapper/sync/event.rb +194 -0
- data/lib/yapper/sync/queue.rb +164 -0
- data/lib/yapper/timestamps.rb +16 -0
- data/lib/yapper/version.rb +3 -0
- data/lib/yapper/yapper.rb +2 -0
- data/spec/helpers/time_helper.rb +3 -0
- data/spec/integration/all_spec.rb +40 -0
- data/spec/integration/callback_spec.rb +87 -0
- data/spec/integration/db_spec.rb +40 -0
- data/spec/integration/find_spec.rb +51 -0
- data/spec/integration/persistance_spec.rb +118 -0
- data/spec/integration/relation_spec.rb +174 -0
- data/spec/integration/sync_spec.rb +42 -0
- data/spec/integration/timestamps_spec.rb +34 -0
- data/spec/integration/types_spec.rb +23 -0
- data/spec/integration/when_spec.rb +29 -0
- data/spec/integration/where_spec.rb +132 -0
- data/vendor/Podfile.lock +24 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.h +641 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.m +1396 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h +133 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m +327 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h +113 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m +321 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h +71 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m +150 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h +75 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m +157 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFNetworking.h +43 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h +68 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m +143 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h +370 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m +848 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h +89 -0
- data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m +167 -0
- data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h +78 -0
- data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m +191 -0
- data/vendor/Pods/AFNetworking/LICENSE +19 -0
- data/vendor/Pods/AFNetworking/README.md +208 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPClient.h +641 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPRequestOperation.h +133 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFImageRequestOperation.h +113 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFJSONRequestOperation.h +71 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworkActivityIndicatorManager.h +75 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworking.h +43 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFPropertyListRequestOperation.h +68 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFURLConnectionOperation.h +370 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/AFXMLRequestOperation.h +89 -0
- data/vendor/Pods/BuildHeaders/AFNetworking/UIImageView+AFNetworking.h +78 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h +65 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +41 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +102 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +334 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +601 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +167 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DispatchQueueLogFormatter.h +116 -0
- data/vendor/Pods/BuildHeaders/NSData+MD5Digest/NSData+MD5Digest.h +18 -0
- data/vendor/Pods/BuildHeaders/Reachability/Reachability.h +109 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapCache.h +90 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapCollectionKey.h +20 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabase.h +547 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnection.h +447 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnectionState.h +29 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseDefaults.h +37 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtension.h +15 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionConnection.h +11 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionPrivate.h +440 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionTransaction.h +11 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredView.h +108 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewConnection.h +12 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewPrivate.h +19 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTransaction.h +39 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearch.h +89 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchConnection.h +32 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchPrivate.h +69 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchSnippetOptions.h +79 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchTransaction.h +68 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseLogging.h +158 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseManager.h +17 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabasePrivate.h +424 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseQuery.h +42 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndex.h +100 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexConnection.h +33 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +73 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetup.h +33 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexTransaction.h +58 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseStatement.h +13 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseString.h +121 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseTransaction.h +541 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseView.h +186 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChange.h +272 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChangePrivate.h +94 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewConnection.h +115 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappings.h +825 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappingsPrivate.h +72 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewOptions.h +56 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPage.h +36 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPageMetadata.h +27 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPrivate.h +153 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewRangeOptions.h +330 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +17 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTransaction.h +447 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapMemoryTable.h +74 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapNull.h +17 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapSet.h +41 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapTouch.h +15 -0
- data/vendor/Pods/CocoaLumberjack/LICENSE.txt +18 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +41 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +99 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +102 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +727 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +334 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +1353 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +601 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +1083 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +167 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +1479 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h +65 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.m +191 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.h +116 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m +251 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/README.txt +7 -0
- data/vendor/Pods/CocoaLumberjack/README.markdown +37 -0
- data/vendor/Pods/Headers/AFNetworking/AFHTTPClient.h +641 -0
- data/vendor/Pods/Headers/AFNetworking/AFHTTPRequestOperation.h +133 -0
- data/vendor/Pods/Headers/AFNetworking/AFImageRequestOperation.h +113 -0
- data/vendor/Pods/Headers/AFNetworking/AFJSONRequestOperation.h +71 -0
- data/vendor/Pods/Headers/AFNetworking/AFNetworkActivityIndicatorManager.h +75 -0
- data/vendor/Pods/Headers/AFNetworking/AFNetworking.h +43 -0
- data/vendor/Pods/Headers/AFNetworking/AFPropertyListRequestOperation.h +68 -0
- data/vendor/Pods/Headers/AFNetworking/AFURLConnectionOperation.h +370 -0
- data/vendor/Pods/Headers/AFNetworking/AFXMLRequestOperation.h +89 -0
- data/vendor/Pods/Headers/AFNetworking/UIImageView+AFNetworking.h +78 -0
- data/vendor/Pods/Headers/CocoaLumberjack/ContextFilterLogFormatter.h +65 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +41 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +102 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +334 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +601 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +167 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DispatchQueueLogFormatter.h +116 -0
- data/vendor/Pods/Headers/NSData+MD5Digest/NSData+MD5Digest.h +18 -0
- data/vendor/Pods/Headers/Reachability/Reachability.h +109 -0
- data/vendor/Pods/Headers/YapDatabase/YapCache.h +90 -0
- data/vendor/Pods/Headers/YapDatabase/YapCollectionKey.h +20 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabase.h +547 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnection.h +447 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnectionState.h +29 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseDefaults.h +37 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtension.h +15 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionConnection.h +11 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionPrivate.h +440 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionTransaction.h +11 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredView.h +108 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewConnection.h +12 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewPrivate.h +19 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTransaction.h +39 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearch.h +89 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchConnection.h +32 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchPrivate.h +69 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchSnippetOptions.h +79 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchTransaction.h +68 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseLogging.h +158 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseManager.h +17 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabasePrivate.h +424 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseQuery.h +42 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndex.h +100 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexConnection.h +33 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +73 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexSetup.h +33 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexTransaction.h +58 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseStatement.h +13 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseString.h +121 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseTransaction.h +541 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseView.h +186 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChange.h +272 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChangePrivate.h +94 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewConnection.h +115 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappings.h +825 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappingsPrivate.h +72 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewOptions.h +56 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPage.h +36 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPageMetadata.h +27 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPrivate.h +153 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptions.h +330 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +17 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTransaction.h +447 -0
- data/vendor/Pods/Headers/YapDatabase/YapMemoryTable.h +74 -0
- data/vendor/Pods/Headers/YapDatabase/YapNull.h +17 -0
- data/vendor/Pods/Headers/YapDatabase/YapSet.h +41 -0
- data/vendor/Pods/Headers/YapDatabase/YapTouch.h +15 -0
- data/vendor/Pods/Headers/____Pods-AFNetworking-prefix.h +17 -0
- data/vendor/Pods/Headers/____Pods-CocoaLumberjack-prefix.h +5 -0
- data/vendor/Pods/Headers/____Pods-NSData+MD5Digest-prefix.h +5 -0
- data/vendor/Pods/Headers/____Pods-Reachability-prefix.h +5 -0
- data/vendor/Pods/Headers/____Pods-YapDatabase-prefix.h +5 -0
- data/vendor/Pods/Headers/____Pods-environment.h +38 -0
- data/vendor/Pods/Manifest.lock +24 -0
- data/vendor/Pods/NSData+MD5Digest/NSData+MD5Digest/NSData+MD5Digest.h +18 -0
- data/vendor/Pods/NSData+MD5Digest/NSData+MD5Digest/NSData+MD5Digest.m +39 -0
- data/vendor/Pods/NSData+MD5Digest/README.md +11 -0
- data/vendor/Pods/Pods-AFNetworking-Private.xcconfig +5 -0
- data/vendor/Pods/Pods-AFNetworking-dummy.m +5 -0
- data/vendor/Pods/Pods-AFNetworking-prefix.pch +17 -0
- data/vendor/Pods/Pods-AFNetworking.xcconfig +1 -0
- data/vendor/Pods/Pods-Acknowledgements.markdown +96 -0
- data/vendor/Pods/Pods-Acknowledgements.plist +142 -0
- data/vendor/Pods/Pods-CocoaLumberjack-Private.xcconfig +5 -0
- data/vendor/Pods/Pods-CocoaLumberjack-dummy.m +5 -0
- data/vendor/Pods/Pods-CocoaLumberjack-prefix.pch +5 -0
- data/vendor/Pods/Pods-CocoaLumberjack.xcconfig +0 -0
- data/vendor/Pods/Pods-NSData+MD5Digest-Private.xcconfig +5 -0
- data/vendor/Pods/Pods-NSData+MD5Digest-dummy.m +5 -0
- data/vendor/Pods/Pods-NSData+MD5Digest-prefix.pch +5 -0
- data/vendor/Pods/Pods-NSData+MD5Digest.xcconfig +0 -0
- data/vendor/Pods/Pods-Reachability-Private.xcconfig +5 -0
- data/vendor/Pods/Pods-Reachability-dummy.m +5 -0
- data/vendor/Pods/Pods-Reachability-prefix.pch +5 -0
- data/vendor/Pods/Pods-Reachability.xcconfig +1 -0
- data/vendor/Pods/Pods-YapDatabase-Private.xcconfig +5 -0
- data/vendor/Pods/Pods-YapDatabase-dummy.m +5 -0
- data/vendor/Pods/Pods-YapDatabase-prefix.pch +5 -0
- data/vendor/Pods/Pods-YapDatabase.xcconfig +1 -0
- data/vendor/Pods/Pods-dummy.m +5 -0
- data/vendor/Pods/Pods-environment.h +38 -0
- data/vendor/Pods/Pods-resources.sh +68 -0
- data/vendor/Pods/Pods.bridgesupport +5096 -0
- data/vendor/Pods/Pods.xcconfig +5 -0
- data/vendor/Pods/Pods.xcodeproj/project.pbxproj +5536 -0
- data/vendor/Pods/Reachability/LICENCE.txt +24 -0
- data/vendor/Pods/Reachability/README.md +65 -0
- data/vendor/Pods/Reachability/Reachability.h +109 -0
- data/vendor/Pods/Reachability/Reachability.m +527 -0
- data/vendor/Pods/YapDatabase/LICENSE.txt +18 -0
- data/vendor/Pods/YapDatabase/README.md +30 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/Internal/YapDatabaseFilteredViewPrivate.h +19 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.h +108 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.m +175 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewConnection.h +12 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewConnection.m +41 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.h +39 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.m +966 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/Internal/YapDatabaseFullTextSearchPrivate.h +69 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.h +89 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.m +146 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.h +32 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.m +298 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchSnippetOptions.h +79 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchSnippetOptions.m +95 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.h +68 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.m +1352 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/Internal/YapDatabaseExtensionPrivate.h +440 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.h +15 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.m +58 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.h +11 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.m +46 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.h +11 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.m +180 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexPrivate.h +73 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.h +100 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m +149 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.h +33 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.m +330 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.h +33 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.m +184 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.h +58 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.m +1166 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewChangePrivate.h +94 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewMappingsPrivate.h +72 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPage.h +36 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPage.mm +296 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPageMetadata.h +27 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPageMetadata.m +28 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPrivate.h +153 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewRangeOptionsPrivate.h +17 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.h +272 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.m +2494 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.h +825 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.m +1567 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewRangeOptions.h +330 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewRangeOptions.m +141 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.h +186 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.m +191 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.h +115 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.m +897 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.h +56 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.m +27 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.h +447 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m +4505 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.h +90 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.m +453 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseConnectionState.h +29 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseConnectionState.m +48 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.h +37 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.m +83 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseLogging.h +158 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseLogging.m +73 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseManager.h +17 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseManager.m +56 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabasePrivate.h +424 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseStatement.h +13 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseStatement.m +26 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseString.h +121 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapMemoryTable.h +74 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapMemoryTable.m +603 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.h +17 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.m +31 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapTouch.h +15 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapTouch.m +31 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.h +20 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.m +194 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapDatabaseQuery.h +42 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapDatabaseQuery.m +96 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapSet.h +41 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapSet.m +82 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.h +547 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.m +2022 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.h +447 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.m +3874 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.h +541 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.m +5282 -0
- data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.bridgesupport +16 -0
- data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.h +13 -0
- data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.m +20 -0
- data/yapper.gemspec +24 -0
- metadata +458 -0
|
@@ -0,0 +1,2494 @@
|
|
|
1
|
+
#import "YapDatabaseViewChange.h"
|
|
2
|
+
#import "YapDatabaseViewChangePrivate.h"
|
|
3
|
+
#import "YapDatabaseViewMappingsPrivate.h"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@implementation YapDatabaseViewSectionChange {
|
|
7
|
+
|
|
8
|
+
/* From YapDatabaseViewChangePrivate.h :
|
|
9
|
+
|
|
10
|
+
@public
|
|
11
|
+
|
|
12
|
+
NSString *group; // immutable
|
|
13
|
+
BOOL isReset; // immutable
|
|
14
|
+
|
|
15
|
+
YapDatabaseViewChangeType type; // mutable during consolidation
|
|
16
|
+
|
|
17
|
+
NSUInteger originalSection; // mutable during pre-processing
|
|
18
|
+
NSUInteger finalSection; // mutable during pre-processing
|
|
19
|
+
*/
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@synthesize type = type;
|
|
23
|
+
@synthesize group = group;
|
|
24
|
+
|
|
25
|
+
+ (YapDatabaseViewSectionChange *)insertGroup:(NSString *)group
|
|
26
|
+
{
|
|
27
|
+
YapDatabaseViewSectionChange *op = [[YapDatabaseViewSectionChange alloc] init];
|
|
28
|
+
op->type = YapDatabaseViewChangeInsert;
|
|
29
|
+
op->group = group;
|
|
30
|
+
op->isReset = NO;
|
|
31
|
+
op->originalSection = op->finalSection = NSNotFound;
|
|
32
|
+
|
|
33
|
+
return op;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
+ (YapDatabaseViewSectionChange *)deleteGroup:(NSString *)group
|
|
37
|
+
{
|
|
38
|
+
YapDatabaseViewSectionChange *op = [[YapDatabaseViewSectionChange alloc] init];
|
|
39
|
+
op->type = YapDatabaseViewChangeDelete;
|
|
40
|
+
op->group = group;
|
|
41
|
+
op->isReset = NO;
|
|
42
|
+
op->originalSection = op->finalSection = NSNotFound;
|
|
43
|
+
|
|
44
|
+
return op;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
+ (YapDatabaseViewSectionChange *)resetGroup:(NSString *)group
|
|
48
|
+
{
|
|
49
|
+
YapDatabaseViewSectionChange *op = [[YapDatabaseViewSectionChange alloc] init];
|
|
50
|
+
op->type = YapDatabaseViewChangeDelete;
|
|
51
|
+
op->group = group;
|
|
52
|
+
op->isReset = YES;
|
|
53
|
+
op->originalSection = op->finalSection = NSNotFound;
|
|
54
|
+
|
|
55
|
+
return op;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
- (id)copyWithZone:(NSZone *)zone
|
|
59
|
+
{
|
|
60
|
+
YapDatabaseViewSectionChange *op = [[YapDatabaseViewSectionChange alloc] init];
|
|
61
|
+
op->type = type;
|
|
62
|
+
op->group = group;
|
|
63
|
+
op->isReset = isReset;
|
|
64
|
+
op->originalSection = originalSection;
|
|
65
|
+
op->finalSection = finalSection;
|
|
66
|
+
|
|
67
|
+
return op;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
- (NSUInteger)index
|
|
71
|
+
{
|
|
72
|
+
if (type == YapDatabaseViewChangeInsert)
|
|
73
|
+
return finalSection;
|
|
74
|
+
else
|
|
75
|
+
return originalSection;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
- (NSString *)description
|
|
79
|
+
{
|
|
80
|
+
if (type == YapDatabaseViewChangeInsert)
|
|
81
|
+
{
|
|
82
|
+
if (finalSection == NSNotFound)
|
|
83
|
+
{
|
|
84
|
+
// Internal style (for debugging the processAndConsolidateOperations method)
|
|
85
|
+
return [NSString stringWithFormat:
|
|
86
|
+
@"<YapDatabaseViewSectionChange: Insert group(%@)", group];
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
{
|
|
90
|
+
// External style (for debugging UITableView & UICollectionView updates)
|
|
91
|
+
return [NSString stringWithFormat:
|
|
92
|
+
@"<YapDatabaseViewSectionChange: Insert section(%lu) group(%@)>",
|
|
93
|
+
(unsigned long)finalSection, group];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else // if (type == YapDatabaseViewChangeDelete)
|
|
97
|
+
{
|
|
98
|
+
if (originalSection == NSNotFound)
|
|
99
|
+
{
|
|
100
|
+
// Internal style (for debugging the processAndConsolidateOperations method)
|
|
101
|
+
return [NSString stringWithFormat:
|
|
102
|
+
@"<YapDatabaseViewSectionChange: Delete group(%@)", group];
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
{
|
|
106
|
+
// External style (for debugging UITableView & UICollectionView updates)
|
|
107
|
+
return [NSString stringWithFormat:
|
|
108
|
+
@"<YapDatabaseViewSectionChange: Delete section(%lu) group(%@)>",
|
|
109
|
+
(unsigned long)originalSection, group];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@end
|
|
115
|
+
|
|
116
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
117
|
+
#pragma mark -
|
|
118
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
119
|
+
|
|
120
|
+
@implementation YapDatabaseViewRowChange {
|
|
121
|
+
|
|
122
|
+
/* From YapDatabaseViewChangePrivate.h :
|
|
123
|
+
|
|
124
|
+
@public
|
|
125
|
+
|
|
126
|
+
id key; // immutable
|
|
127
|
+
|
|
128
|
+
NSString *originalGroup; // immutable
|
|
129
|
+
NSString *finalGroup; // mutable during consolidation
|
|
130
|
+
|
|
131
|
+
YapDatabaseViewChangeType type; // mutable during consolidation
|
|
132
|
+
int columns; // mutable during consolidation
|
|
133
|
+
|
|
134
|
+
NSUInteger opOriginalIndex; // immutable
|
|
135
|
+
NSUInteger opFinalIndex; // immutable
|
|
136
|
+
|
|
137
|
+
NSUInteger originalIndex; // mutable during processing
|
|
138
|
+
NSUInteger finalIndex; // mutable during processing
|
|
139
|
+
|
|
140
|
+
NSUInteger originalSection; // mutable during pre-processing
|
|
141
|
+
NSUInteger finalSection; // mutable during pre-processing
|
|
142
|
+
*/
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@synthesize type = type;
|
|
146
|
+
@synthesize changes = changes;
|
|
147
|
+
@synthesize originalGroup = originalGroup;
|
|
148
|
+
@synthesize finalGroup = finalGroup;
|
|
149
|
+
@synthesize originalIndex = originalIndex;
|
|
150
|
+
@synthesize finalIndex = finalIndex;
|
|
151
|
+
@synthesize originalSection = originalSection;
|
|
152
|
+
@synthesize finalSection = finalSection;
|
|
153
|
+
|
|
154
|
+
- (NSIndexPath *)indexPath
|
|
155
|
+
{
|
|
156
|
+
if (type == YapDatabaseViewChangeInsert) {
|
|
157
|
+
return nil; // <-- You should be using newIndexPath
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
{
|
|
161
|
+
#if TARGET_OS_IPHONE
|
|
162
|
+
return [NSIndexPath indexPathForRow:originalIndex inSection:originalSection];
|
|
163
|
+
#else
|
|
164
|
+
NSUInteger indexes[] = {originalSection, originalIndex};
|
|
165
|
+
return [NSIndexPath indexPathWithIndexes:indexes length:2];
|
|
166
|
+
#endif
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
- (NSIndexPath *)newIndexPath
|
|
171
|
+
{
|
|
172
|
+
if (type == YapDatabaseViewChangeDelete || type == YapDatabaseViewChangeUpdate) {
|
|
173
|
+
return nil; // <-- You should be using indexPath
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
#if TARGET_OS_IPHONE
|
|
177
|
+
return [NSIndexPath indexPathForRow:finalIndex inSection:finalSection];
|
|
178
|
+
#else
|
|
179
|
+
NSUInteger indexes[] = {finalSection, finalIndex};
|
|
180
|
+
return [NSIndexPath indexPathWithIndexes:indexes length:2];
|
|
181
|
+
#endif
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
- (id)copyWithZone:(NSZone *)zone
|
|
186
|
+
{
|
|
187
|
+
YapDatabaseViewRowChange *op = [[YapDatabaseViewRowChange alloc] init];
|
|
188
|
+
op->key = key;
|
|
189
|
+
op->originalGroup = originalGroup;
|
|
190
|
+
op->finalGroup = finalGroup;
|
|
191
|
+
op->type = type;
|
|
192
|
+
op->changes = changes;
|
|
193
|
+
op->opOriginalIndex = opOriginalIndex;
|
|
194
|
+
op->opFinalIndex = opFinalIndex;
|
|
195
|
+
op->originalIndex = originalIndex;
|
|
196
|
+
op->finalIndex = finalIndex;
|
|
197
|
+
op->originalSection = originalSection;
|
|
198
|
+
op->finalSection = finalSection;
|
|
199
|
+
|
|
200
|
+
return op;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
+ (YapDatabaseViewRowChange *)insertKey:(id)key inGroup:(NSString *)group atIndex:(NSUInteger)index
|
|
204
|
+
{
|
|
205
|
+
YapDatabaseViewRowChange *op = [[YapDatabaseViewRowChange alloc] init];
|
|
206
|
+
op->type = YapDatabaseViewChangeInsert;
|
|
207
|
+
op->key = key;
|
|
208
|
+
op->changes = YapDatabaseViewChangedObject | YapDatabaseViewChangedMetadata;
|
|
209
|
+
|
|
210
|
+
op->originalGroup = nil; // invalid in insert type
|
|
211
|
+
op->originalIndex = op->opOriginalIndex = NSNotFound; // invalid in insert type
|
|
212
|
+
|
|
213
|
+
op->finalGroup = group;
|
|
214
|
+
op->finalIndex = op->opFinalIndex = index;
|
|
215
|
+
|
|
216
|
+
op->originalSection = op->finalSection = NSNotFound;
|
|
217
|
+
|
|
218
|
+
return op;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
+ (YapDatabaseViewRowChange *)deleteKey:(id)key inGroup:(NSString *)group atIndex:(NSUInteger)index
|
|
222
|
+
{
|
|
223
|
+
YapDatabaseViewRowChange *op = [[YapDatabaseViewRowChange alloc] init];
|
|
224
|
+
op->type = YapDatabaseViewChangeDelete;
|
|
225
|
+
op->key = key;
|
|
226
|
+
op->changes = YapDatabaseViewChangedObject | YapDatabaseViewChangedMetadata;
|
|
227
|
+
|
|
228
|
+
op->originalGroup = group;
|
|
229
|
+
op->originalIndex = op->opOriginalIndex = index;
|
|
230
|
+
|
|
231
|
+
op->finalGroup = nil; // invalid in delete type
|
|
232
|
+
op->finalIndex = op->opFinalIndex = NSNotFound; // invalid in delete type
|
|
233
|
+
|
|
234
|
+
op->originalSection = op->finalSection = NSNotFound;
|
|
235
|
+
|
|
236
|
+
return op;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
+ (YapDatabaseViewRowChange *)updateKey:(id)key changes:(int)flags inGroup:(NSString *)group atIndex:(NSUInteger)index
|
|
240
|
+
{
|
|
241
|
+
YapDatabaseViewRowChange *op = [[YapDatabaseViewRowChange alloc] init];
|
|
242
|
+
op->type = YapDatabaseViewChangeUpdate;
|
|
243
|
+
op->key = key;
|
|
244
|
+
op->changes = flags;
|
|
245
|
+
|
|
246
|
+
op->originalGroup = group;
|
|
247
|
+
op->originalIndex = op->opOriginalIndex = index;
|
|
248
|
+
|
|
249
|
+
op->finalGroup = group;
|
|
250
|
+
op->finalIndex = op->opFinalIndex = index;
|
|
251
|
+
|
|
252
|
+
op->originalSection = op->finalSection = NSNotFound;
|
|
253
|
+
|
|
254
|
+
return op;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
- (NSString *)description
|
|
258
|
+
{
|
|
259
|
+
if (type == YapDatabaseViewChangeInsert)
|
|
260
|
+
{
|
|
261
|
+
if (finalSection == NSNotFound)
|
|
262
|
+
{
|
|
263
|
+
// Internal style (for debugging the processAndConsolidateOperations method)
|
|
264
|
+
return [NSString stringWithFormat:
|
|
265
|
+
@"<YapDatabaseViewRowChange: Insert pre(~ -> %lu) post(~ -> %lu) group(%@) key(%@)",
|
|
266
|
+
(unsigned long)opFinalIndex, (unsigned long)finalIndex, finalGroup, key];
|
|
267
|
+
}
|
|
268
|
+
else
|
|
269
|
+
{
|
|
270
|
+
// External style (for debugging UITableView & UICollectionView updates)
|
|
271
|
+
return [NSString stringWithFormat:
|
|
272
|
+
@"<YapDatabaseViewRowChange: Insert indexPath(nil) newIndexPath(%lu, %lu) group(%@) key(%@)>",
|
|
273
|
+
(unsigned long)finalSection, (unsigned long)finalIndex, finalGroup, key];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else if (type == YapDatabaseViewChangeDelete)
|
|
277
|
+
{
|
|
278
|
+
if (originalSection == NSNotFound)
|
|
279
|
+
{
|
|
280
|
+
// Internal style (for debugging the processAndConsolidateOperations method)
|
|
281
|
+
return [NSString stringWithFormat:
|
|
282
|
+
@"<YapDatabaseViewRowChange: Delete pre(%lu -> ~) post(%lu -> ~) group(%@) key(%@)",
|
|
283
|
+
(unsigned long)opOriginalIndex, (unsigned long)originalIndex, originalGroup, key];
|
|
284
|
+
}
|
|
285
|
+
else
|
|
286
|
+
{
|
|
287
|
+
// External style (for debugging UITableView & UICollectionView updates)
|
|
288
|
+
return [NSString stringWithFormat:
|
|
289
|
+
@"<YapDatabaseViewRowChange: Delete indexPath(%lu, %lu) newIndexPath(nil) group(%@) key(%@)>",
|
|
290
|
+
(unsigned long)originalSection, (unsigned long)originalIndex, originalGroup, key];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
else if (type == YapDatabaseViewChangeMove)
|
|
294
|
+
{
|
|
295
|
+
if (originalSection == NSNotFound && finalSection == NSNotFound)
|
|
296
|
+
{
|
|
297
|
+
// Internal style (for debugging the processAndConsolidateOperations method)
|
|
298
|
+
return [NSString stringWithFormat:
|
|
299
|
+
@"<YapDatabaseViewRowChange: Move pre(%lu -> %lu) post(%lu -> %lu) group(%@ -> %@) key(%@)",
|
|
300
|
+
(unsigned long)opOriginalIndex, (unsigned long)opFinalIndex,
|
|
301
|
+
(unsigned long)originalIndex, (unsigned long)finalIndex,
|
|
302
|
+
originalGroup, finalGroup, key];
|
|
303
|
+
}
|
|
304
|
+
else
|
|
305
|
+
{
|
|
306
|
+
// External style (for debugging UITableView & UICollectionView updates)
|
|
307
|
+
return [NSString stringWithFormat:
|
|
308
|
+
@"<YapDatabaseViewRowChange: Move indexPath(%lu, %lu) newIndexPath(%lu, %lu) group(%@ -> %@) key(%@)",
|
|
309
|
+
(unsigned long)originalSection, (unsigned long)originalIndex,
|
|
310
|
+
(unsigned long)finalSection, (unsigned long)finalIndex,
|
|
311
|
+
originalGroup, finalGroup, key];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else // if (type == YapDatabaseViewChangeUpdate)
|
|
315
|
+
{
|
|
316
|
+
if (originalSection == NSNotFound && finalSection == NSNotFound)
|
|
317
|
+
{
|
|
318
|
+
// Internal style (for debugging the processAndConsolidateOperations method)
|
|
319
|
+
return [NSString stringWithFormat:
|
|
320
|
+
@"<YapDatabaseViewRowChange: Update pre(%lu) post(%lu -> %lu) group(%@) key(%@)",
|
|
321
|
+
(unsigned long)opOriginalIndex,
|
|
322
|
+
(unsigned long)originalIndex, (unsigned long)finalIndex, originalGroup, key];
|
|
323
|
+
}
|
|
324
|
+
else
|
|
325
|
+
{
|
|
326
|
+
// External style (for debugging UITableView & UICollectionView updates)
|
|
327
|
+
return [NSString stringWithFormat:
|
|
328
|
+
@"<YapDatabaseViewRowChange: Update indexPath(%lu, %lu) group(%@) key(%@)",
|
|
329
|
+
(unsigned long)originalSection, (unsigned long)originalIndex, originalGroup, key];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@end
|
|
335
|
+
|
|
336
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
337
|
+
#pragma mark -
|
|
338
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
339
|
+
|
|
340
|
+
@implementation YapDatabaseViewChange
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* During a read-write transaction, every modification to the view results in one or more
|
|
344
|
+
* YapDatabaseViewSectionChange or YapDatabaseViewRowChange objects being appended to an internal array.
|
|
345
|
+
*
|
|
346
|
+
* At the end of the read-write transaction we have a big list of changes that have occurred.
|
|
347
|
+
*
|
|
348
|
+
* This method takes the original list and pre-processes it:
|
|
349
|
+
*
|
|
350
|
+
* - splits the array in sectionChanges and rowChanges
|
|
351
|
+
* - removes any items from the changes array that don't concern us (group not in mappings)
|
|
352
|
+
* - injects extra changes if there are cell dependencies configured in the mappings
|
|
353
|
+
**/
|
|
354
|
+
+ (void)preProcessChanges:(NSArray *)changes
|
|
355
|
+
withOriginalMappings:(YapDatabaseViewMappings *)originalMappings
|
|
356
|
+
finalMappings:(YapDatabaseViewMappings *)finalMappings
|
|
357
|
+
andGetSectionChanges:(NSMutableArray **)sectionChangesPtr
|
|
358
|
+
rowChanges:(NSMutableArray **)rowChangesPtr
|
|
359
|
+
{
|
|
360
|
+
|
|
361
|
+
// We remove any items from the changes array that don't concern us.
|
|
362
|
+
// For example, if mappings only contain groupA & groupB,
|
|
363
|
+
// then we can ignore changes in groupC.
|
|
364
|
+
//
|
|
365
|
+
// We also may need to inject extra changes.
|
|
366
|
+
// The user may specify, as a configuration option within mappings,
|
|
367
|
+
// the the drawing of cells has an dependency upon neighboring cells.
|
|
368
|
+
|
|
369
|
+
NSMutableArray *sectionChanges = [NSMutableArray arrayWithCapacity:1];
|
|
370
|
+
NSMutableArray *rowChanges = [NSMutableArray arrayWithCapacity:[changes count]];
|
|
371
|
+
|
|
372
|
+
NSSet *groups = [NSSet setWithArray:[originalMappings allGroups]];
|
|
373
|
+
|
|
374
|
+
NSMutableDictionary *counts = [originalMappings counts];
|
|
375
|
+
NSDictionary *dependencies = [originalMappings dependencies];
|
|
376
|
+
|
|
377
|
+
for (id change in changes)
|
|
378
|
+
{
|
|
379
|
+
if ([change isKindOfClass:[YapDatabaseViewSectionChange class]])
|
|
380
|
+
{
|
|
381
|
+
__unsafe_unretained YapDatabaseViewSectionChange *immutableSectionChange =
|
|
382
|
+
(YapDatabaseViewSectionChange *)change;
|
|
383
|
+
|
|
384
|
+
if (immutableSectionChange->type == YapDatabaseViewChangeDelete)
|
|
385
|
+
{
|
|
386
|
+
if ([groups containsObject:immutableSectionChange->group])
|
|
387
|
+
{
|
|
388
|
+
YapDatabaseViewSectionChange *sectionChange = [immutableSectionChange copy];
|
|
389
|
+
[sectionChanges addObject:sectionChange];
|
|
390
|
+
|
|
391
|
+
if (sectionChange->isReset)
|
|
392
|
+
{
|
|
393
|
+
// Special case processing.
|
|
394
|
+
//
|
|
395
|
+
// Most of the time, groups are deleted because the last key within the group was removed.
|
|
396
|
+
// Thus a regular section delete is accompanied by all the corresponding row deletes.
|
|
397
|
+
// But if the user invokes:
|
|
398
|
+
// - removeAllObjectsInAllCollections
|
|
399
|
+
//
|
|
400
|
+
// then we get a section delete that isn't accompanied by the corresponding row deletes.
|
|
401
|
+
// This operation is flagged via isReset.
|
|
402
|
+
//
|
|
403
|
+
// So here's what we do in this situation:
|
|
404
|
+
// - remove any previous row changes within the group
|
|
405
|
+
// - manually inject all the proper row deletes
|
|
406
|
+
|
|
407
|
+
__unsafe_unretained YapDatabaseViewRowChange *rowChange;
|
|
408
|
+
|
|
409
|
+
for (NSUInteger i = [rowChanges count]; i > 0; i--)
|
|
410
|
+
{
|
|
411
|
+
rowChange = [rowChanges objectAtIndex:(i-1)];
|
|
412
|
+
|
|
413
|
+
if (rowChange->type == YapDatabaseViewChangeDelete)
|
|
414
|
+
{
|
|
415
|
+
if ([rowChange->originalGroup isEqualToString:sectionChange->group])
|
|
416
|
+
{
|
|
417
|
+
[rowChanges removeObjectAtIndex:(i-1)];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
else // YapDatabaseViewChangeInsert || YapDatabaseViewChangeUpdate
|
|
421
|
+
{
|
|
422
|
+
if ([rowChange->finalGroup isEqualToString:sectionChange->group])
|
|
423
|
+
{
|
|
424
|
+
[rowChanges removeObjectAtIndex:(i-1)];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
YapDatabaseViewRangePosition rangePosition =
|
|
430
|
+
[originalMappings rangePositionForGroup:sectionChange->group];
|
|
431
|
+
|
|
432
|
+
NSUInteger prevRowOffset = rangePosition.offsetFromBeginning;
|
|
433
|
+
NSUInteger prevRowCount = rangePosition.length;
|
|
434
|
+
|
|
435
|
+
while (prevRowCount > 0)
|
|
436
|
+
{
|
|
437
|
+
YapDatabaseViewRowChange *rowChange =
|
|
438
|
+
[YapDatabaseViewRowChange deleteKey:nil
|
|
439
|
+
inGroup:sectionChange->group
|
|
440
|
+
atIndex:(prevRowOffset+prevRowCount-1)];
|
|
441
|
+
|
|
442
|
+
[rowChanges addObject:rowChange];
|
|
443
|
+
prevRowCount--;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
[counts setObject:@(0) forKey:sectionChange->group];
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
else if (immutableSectionChange->type == YapDatabaseViewChangeInsert)
|
|
451
|
+
{
|
|
452
|
+
if ([groups containsObject:immutableSectionChange->group])
|
|
453
|
+
{
|
|
454
|
+
YapDatabaseViewSectionChange *sectionChange = [immutableSectionChange copy];
|
|
455
|
+
[sectionChanges addObject:sectionChange];
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else
|
|
460
|
+
{
|
|
461
|
+
__unsafe_unretained YapDatabaseViewRowChange *immutableRowChange = (YapDatabaseViewRowChange *)change;
|
|
462
|
+
|
|
463
|
+
__unsafe_unretained NSString *group = nil;
|
|
464
|
+
NSUInteger groupCount = 0;
|
|
465
|
+
NSUInteger groupIndex = 0;
|
|
466
|
+
BOOL wasDelete = 0;
|
|
467
|
+
|
|
468
|
+
if (immutableRowChange->type == YapDatabaseViewChangeDelete)
|
|
469
|
+
{
|
|
470
|
+
if ([groups containsObject:immutableRowChange->originalGroup])
|
|
471
|
+
{
|
|
472
|
+
YapDatabaseViewRowChange *rowChange = [immutableRowChange copy];
|
|
473
|
+
[rowChanges addObject:rowChange];
|
|
474
|
+
|
|
475
|
+
group = rowChange->originalGroup;
|
|
476
|
+
groupIndex = rowChange->originalIndex;
|
|
477
|
+
|
|
478
|
+
groupCount = [[counts objectForKey:group] unsignedIntegerValue];
|
|
479
|
+
groupCount--;
|
|
480
|
+
[counts setObject:@(groupCount) forKey:group];
|
|
481
|
+
|
|
482
|
+
wasDelete = YES;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
else if (immutableRowChange->type == YapDatabaseViewChangeInsert)
|
|
486
|
+
{
|
|
487
|
+
if ([groups containsObject:immutableRowChange->finalGroup])
|
|
488
|
+
{
|
|
489
|
+
YapDatabaseViewRowChange *rowChange = [immutableRowChange copy];
|
|
490
|
+
[rowChanges addObject:rowChange];
|
|
491
|
+
|
|
492
|
+
group = rowChange->finalGroup;
|
|
493
|
+
groupIndex = rowChange->finalIndex;
|
|
494
|
+
|
|
495
|
+
groupCount = [[counts objectForKey:group] unsignedIntegerValue];
|
|
496
|
+
groupCount++;
|
|
497
|
+
[counts setObject:@(groupCount) forKey:group];
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else if (immutableRowChange->type == YapDatabaseViewChangeUpdate)
|
|
501
|
+
{
|
|
502
|
+
if ([groups containsObject:immutableRowChange->originalGroup])
|
|
503
|
+
{
|
|
504
|
+
YapDatabaseViewRowChange *rowChange = [immutableRowChange copy];
|
|
505
|
+
[rowChanges addObject:rowChange];
|
|
506
|
+
|
|
507
|
+
group = rowChange->originalGroup;
|
|
508
|
+
groupIndex = rowChange->originalIndex;
|
|
509
|
+
|
|
510
|
+
groupCount = [[counts objectForKey:group] unsignedIntegerValue];
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Handle cell drawing dependencies.
|
|
515
|
+
|
|
516
|
+
NSSet *dependenciesForGroup = [dependencies objectForKey:group];
|
|
517
|
+
for (NSNumber *offsetNum in dependenciesForGroup)
|
|
518
|
+
{
|
|
519
|
+
NSInteger offset = [offsetNum integerValue] * -1;
|
|
520
|
+
NSUInteger dependencyIndex = groupCount;
|
|
521
|
+
|
|
522
|
+
if (offset > 0)
|
|
523
|
+
{
|
|
524
|
+
dependencyIndex = groupIndex + offset;
|
|
525
|
+
if (wasDelete)
|
|
526
|
+
dependencyIndex--;
|
|
527
|
+
}
|
|
528
|
+
else if ((offset < 0) && (-1*offset <= groupIndex))
|
|
529
|
+
{
|
|
530
|
+
dependencyIndex = groupIndex + offset;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (dependencyIndex < groupCount)
|
|
534
|
+
{
|
|
535
|
+
int changes = YapDatabaseViewChangedDependency;
|
|
536
|
+
|
|
537
|
+
YapDatabaseViewRowChange *rowChange =
|
|
538
|
+
[YapDatabaseViewRowChange updateKey:nil changes:changes inGroup:group atIndex:dependencyIndex];
|
|
539
|
+
|
|
540
|
+
[rowChanges addObject:rowChange];
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (sectionChangesPtr) *sectionChangesPtr = sectionChanges;
|
|
548
|
+
if (rowChangesPtr) *rowChangesPtr = rowChanges;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* During a read-write transaction, every modification to the view results in one or more
|
|
554
|
+
* YapDatabaseViewSectionChange or YapDatabaseViewRowChange objects being appended to an internal array.
|
|
555
|
+
*
|
|
556
|
+
* At the end of the read-write transaction we have a big list of changes that have occurred.
|
|
557
|
+
* But each change represents the change state at the moment the change took place.
|
|
558
|
+
* And we ultimately need to get the change state to reflect the original and/or final position of the change.
|
|
559
|
+
*
|
|
560
|
+
* This method takes a list of YapDatabaseViewRowChange objects and processes them to
|
|
561
|
+
* properly calculate and set the original and/or final index of each row change.
|
|
562
|
+
**/
|
|
563
|
+
+ (void)processRowChanges:(NSMutableArray *)changes
|
|
564
|
+
{
|
|
565
|
+
// Each YapDatabaseViewRowChange object is one of:
|
|
566
|
+
//
|
|
567
|
+
// - Row insert
|
|
568
|
+
// - Row delete
|
|
569
|
+
// - Row update
|
|
570
|
+
//
|
|
571
|
+
// If a row is moved, then it is represented in the given array as a delete followed by an insert.
|
|
572
|
+
//
|
|
573
|
+
// Each YapDatabaseViewRowChange represents the change state AT THE MOMENT THE CHANGE TOOK PLACE.
|
|
574
|
+
// This is critically important to understand.
|
|
575
|
+
//
|
|
576
|
+
// For example, imagine the following array:
|
|
577
|
+
// @[
|
|
578
|
+
// <RowInsert group=fruit index=0 key=apple>
|
|
579
|
+
// <RowDelete group=fruit index=7 key=carrot>
|
|
580
|
+
// <RowInsert group=fruit index=2 key=blueberry>
|
|
581
|
+
// <RowInsert group=fruit index=2 key=banana>
|
|
582
|
+
// ]
|
|
583
|
+
//
|
|
584
|
+
// What was the original index of 'carrot'?
|
|
585
|
+
// What is the final index of 'blueberry'?
|
|
586
|
+
//
|
|
587
|
+
// The original index of 'carrot' was 6, because the earlier insert of 'apple' pushed its index upward.
|
|
588
|
+
// The final index of 'blueberry' is 3, because a later insert of 'banana' pushed its index upward.
|
|
589
|
+
//
|
|
590
|
+
// As you might guess, there are a number of edge cases to watch out for.
|
|
591
|
+
// Ultimately, the algorithm is fairly straight-forward, but the code gets a little verbose.
|
|
592
|
+
//
|
|
593
|
+
// There are are crap ton of unit tests for this code...
|
|
594
|
+
//
|
|
595
|
+
// Please see the UNIT TESTS for a bunch of examples that may shed additional light on the algorithm:
|
|
596
|
+
// TestViewChangeLogic.m
|
|
597
|
+
|
|
598
|
+
NSUInteger i;
|
|
599
|
+
NSUInteger j;
|
|
600
|
+
|
|
601
|
+
// First we enumerate the items BACKWARDS,
|
|
602
|
+
// and update the ORIGINAL values.
|
|
603
|
+
|
|
604
|
+
NSUInteger count = [changes count];
|
|
605
|
+
|
|
606
|
+
for (i = count; i > 0; i--)
|
|
607
|
+
{
|
|
608
|
+
YapDatabaseViewRowChange *change = [changes objectAtIndex:(i-1)];
|
|
609
|
+
|
|
610
|
+
if (change->type == YapDatabaseViewChangeDelete)
|
|
611
|
+
{
|
|
612
|
+
// A DELETE operation may affect the ORIGINAL index value of operations that occurred AFTER it,
|
|
613
|
+
// IF the later operation occurs at a greater or equal index value. ( +1 )
|
|
614
|
+
|
|
615
|
+
for (j = i; j < count; j++)
|
|
616
|
+
{
|
|
617
|
+
YapDatabaseViewRowChange *laterChange = [changes objectAtIndex:j];
|
|
618
|
+
|
|
619
|
+
if (laterChange->type == YapDatabaseViewChangeDelete ||
|
|
620
|
+
laterChange->type == YapDatabaseViewChangeUpdate)
|
|
621
|
+
{
|
|
622
|
+
if (laterChange->originalIndex >= change->opOriginalIndex &&
|
|
623
|
+
[laterChange->originalGroup isEqualToString:change->originalGroup])
|
|
624
|
+
{
|
|
625
|
+
laterChange->originalIndex += 1;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else if (change->type == YapDatabaseViewChangeInsert)
|
|
631
|
+
{
|
|
632
|
+
// An INSERT operation may affect the ORIGINAL index value of operations that occurred AFTER it,
|
|
633
|
+
// IF the later operation occurs at a greater or equal index value. ( -1 )
|
|
634
|
+
|
|
635
|
+
for (j = i; j < count; j++)
|
|
636
|
+
{
|
|
637
|
+
YapDatabaseViewRowChange *laterChange = [changes objectAtIndex:j];
|
|
638
|
+
|
|
639
|
+
if (laterChange->type == YapDatabaseViewChangeDelete ||
|
|
640
|
+
laterChange->type == YapDatabaseViewChangeUpdate)
|
|
641
|
+
{
|
|
642
|
+
if (laterChange->originalIndex >= change->opFinalIndex &&
|
|
643
|
+
[laterChange->originalGroup isEqualToString:change->finalGroup])
|
|
644
|
+
{
|
|
645
|
+
laterChange->originalIndex -= 1;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Next we enumerate the items FORWARDS,
|
|
653
|
+
// and update the FINAL values.
|
|
654
|
+
|
|
655
|
+
for (i = 1; i < count; i++)
|
|
656
|
+
{
|
|
657
|
+
YapDatabaseViewRowChange *change = [changes objectAtIndex:i];
|
|
658
|
+
|
|
659
|
+
if (change->type == YapDatabaseViewChangeDelete)
|
|
660
|
+
{
|
|
661
|
+
// A DELETE operation may affect the FINAL index value of operations that occurred BEFORE it,
|
|
662
|
+
// IF the earlier operation occurs at a greater (but not equal) index value. ( -1 )
|
|
663
|
+
|
|
664
|
+
for (j = i; j > 0; j--)
|
|
665
|
+
{
|
|
666
|
+
YapDatabaseViewRowChange *earlierChange = [changes objectAtIndex:(j-1)];
|
|
667
|
+
|
|
668
|
+
if (earlierChange->type == YapDatabaseViewChangeInsert ||
|
|
669
|
+
earlierChange->type == YapDatabaseViewChangeUpdate )
|
|
670
|
+
{
|
|
671
|
+
if (earlierChange->finalIndex > change->opOriginalIndex &&
|
|
672
|
+
[earlierChange->finalGroup isEqualToString:change->originalGroup])
|
|
673
|
+
{
|
|
674
|
+
earlierChange->finalIndex -= 1;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
else if (change->type == YapDatabaseViewChangeInsert)
|
|
680
|
+
{
|
|
681
|
+
// An INSERT operation may affect the FINAL index value of operations that occurred BEFORE it,
|
|
682
|
+
// IF the earlier operation occurs at a greater index value ( +1 )
|
|
683
|
+
|
|
684
|
+
for (j = i; j > 0; j--)
|
|
685
|
+
{
|
|
686
|
+
YapDatabaseViewRowChange *earlierChange = [changes objectAtIndex:(j-1)];
|
|
687
|
+
|
|
688
|
+
if (earlierChange->type == YapDatabaseViewChangeInsert ||
|
|
689
|
+
earlierChange->type == YapDatabaseViewChangeUpdate)
|
|
690
|
+
{
|
|
691
|
+
if (earlierChange->finalIndex >= change->opFinalIndex &&
|
|
692
|
+
[earlierChange->finalGroup isEqualToString:change->finalGroup])
|
|
693
|
+
{
|
|
694
|
+
earlierChange->finalIndex += 1;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* This method consolidates multiple changes to the same row into a single change that reflects
|
|
704
|
+
* the original and final position of each changed row.
|
|
705
|
+
**/
|
|
706
|
+
+ (void)consolidateRowChanges:(NSMutableArray *)changes
|
|
707
|
+
{
|
|
708
|
+
NSUInteger i;
|
|
709
|
+
NSUInteger j;
|
|
710
|
+
|
|
711
|
+
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
|
|
712
|
+
|
|
713
|
+
i = 0;
|
|
714
|
+
while (i < [changes count])
|
|
715
|
+
{
|
|
716
|
+
YapDatabaseViewRowChange *firstChangeForKey = [changes objectAtIndex:i];
|
|
717
|
+
YapDatabaseViewRowChange *mostRecentChangeForKey = firstChangeForKey;
|
|
718
|
+
|
|
719
|
+
// Find later operations with the same key
|
|
720
|
+
|
|
721
|
+
for (j = i+1; j < [changes count]; j++)
|
|
722
|
+
{
|
|
723
|
+
YapDatabaseViewRowChange *laterChange = [changes objectAtIndex:j];
|
|
724
|
+
BOOL changesAreForSameKey = NO;
|
|
725
|
+
|
|
726
|
+
if (firstChangeForKey->key && laterChange->key)
|
|
727
|
+
{
|
|
728
|
+
// Compare keys
|
|
729
|
+
|
|
730
|
+
if ([laterChange->key isEqual:firstChangeForKey->key])
|
|
731
|
+
changesAreForSameKey = YES;
|
|
732
|
+
}
|
|
733
|
+
else
|
|
734
|
+
{
|
|
735
|
+
// Compare indexes & groups
|
|
736
|
+
//
|
|
737
|
+
// This technique is used if one of the keys is nil,
|
|
738
|
+
// and applies to situations where one of the changes is an Update with a nil key,
|
|
739
|
+
// which was injected during pre-processing due to cell drawing dependencies.
|
|
740
|
+
|
|
741
|
+
if (mostRecentChangeForKey->type == YapDatabaseViewChangeUpdate)
|
|
742
|
+
{
|
|
743
|
+
if (laterChange->type == YapDatabaseViewChangeUpdate ||
|
|
744
|
+
laterChange->type == YapDatabaseViewChangeDelete)
|
|
745
|
+
{
|
|
746
|
+
if (mostRecentChangeForKey->originalIndex == laterChange->originalIndex &&
|
|
747
|
+
[mostRecentChangeForKey->originalGroup isEqualToString:laterChange->originalGroup]) {
|
|
748
|
+
changesAreForSameKey = YES;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
else if (mostRecentChangeForKey->type == YapDatabaseViewChangeInsert)
|
|
753
|
+
{
|
|
754
|
+
if (laterChange->type == YapDatabaseViewChangeUpdate)
|
|
755
|
+
{
|
|
756
|
+
if (mostRecentChangeForKey->originalIndex == laterChange->originalIndex &&
|
|
757
|
+
[mostRecentChangeForKey->originalGroup isEqualToString:laterChange->originalGroup]) {
|
|
758
|
+
changesAreForSameKey = YES;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (changesAreForSameKey)
|
|
764
|
+
{
|
|
765
|
+
if (mostRecentChangeForKey->key == nil)
|
|
766
|
+
mostRecentChangeForKey->key = laterChange->key;
|
|
767
|
+
else
|
|
768
|
+
laterChange->key = mostRecentChangeForKey->key;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (changesAreForSameKey)
|
|
773
|
+
{
|
|
774
|
+
firstChangeForKey->changes |= laterChange->changes;
|
|
775
|
+
[indexSet addIndex:j];
|
|
776
|
+
|
|
777
|
+
mostRecentChangeForKey = laterChange;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if ([indexSet count] == 0)
|
|
782
|
+
{
|
|
783
|
+
i++; // continue;
|
|
784
|
+
}
|
|
785
|
+
else
|
|
786
|
+
{
|
|
787
|
+
YapDatabaseViewRowChange *lastChangeForKey = [changes objectAtIndex:[indexSet lastIndex]];
|
|
788
|
+
|
|
789
|
+
if (firstChangeForKey->type == YapDatabaseViewChangeDelete)
|
|
790
|
+
{
|
|
791
|
+
if (lastChangeForKey->type == YapDatabaseViewChangeDelete)
|
|
792
|
+
{
|
|
793
|
+
// Delete + Insert + ... + Delete
|
|
794
|
+
//
|
|
795
|
+
// All operations except the first are no-ops
|
|
796
|
+
|
|
797
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
798
|
+
i++;
|
|
799
|
+
}
|
|
800
|
+
else if (lastChangeForKey->type == YapDatabaseViewChangeInsert)
|
|
801
|
+
{
|
|
802
|
+
// Delete + Insert = Move
|
|
803
|
+
//
|
|
804
|
+
// This is always a move operation.
|
|
805
|
+
// Even if the final location hasn't ultimately changed, we still want to treat it as a move.
|
|
806
|
+
// Only a true update, where the index never budged, can be emitted as an update.
|
|
807
|
+
//
|
|
808
|
+
// If we attempt to consolidate this into an update,
|
|
809
|
+
// then the tableView/collectionView will offset the update's index
|
|
810
|
+
// based on insertions & deletions at smaller indexes,
|
|
811
|
+
// and may ultimately update the wrong cell.
|
|
812
|
+
|
|
813
|
+
firstChangeForKey->type = YapDatabaseViewChangeMove;
|
|
814
|
+
firstChangeForKey->finalIndex = lastChangeForKey->finalIndex;
|
|
815
|
+
firstChangeForKey->finalGroup = lastChangeForKey->finalGroup;
|
|
816
|
+
|
|
817
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
818
|
+
i++;
|
|
819
|
+
}
|
|
820
|
+
else if (lastChangeForKey->type == YapDatabaseViewChangeUpdate)
|
|
821
|
+
{
|
|
822
|
+
// Delete + Insert + ... + Update = Move
|
|
823
|
+
//
|
|
824
|
+
// This is always a move operation.
|
|
825
|
+
// Even if the final location hasn't ultimately changed, we still want to treat it as a move.
|
|
826
|
+
// Only a true update, where the index never budged, can be emitted as an update.
|
|
827
|
+
//
|
|
828
|
+
// If we attempt to consolidate this into an update,
|
|
829
|
+
// then the tableView/collectionView will offset the update's index
|
|
830
|
+
// based on insertions & deletions at smaller indexes,
|
|
831
|
+
// and may ultimately update the wrong cell.
|
|
832
|
+
|
|
833
|
+
firstChangeForKey->type = YapDatabaseViewChangeMove;
|
|
834
|
+
firstChangeForKey->finalIndex = lastChangeForKey->finalIndex;
|
|
835
|
+
firstChangeForKey->finalGroup = lastChangeForKey->finalGroup;
|
|
836
|
+
|
|
837
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
838
|
+
i++;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
else if (firstChangeForKey->type == YapDatabaseViewChangeInsert)
|
|
842
|
+
{
|
|
843
|
+
if (lastChangeForKey->type == YapDatabaseViewChangeDelete)
|
|
844
|
+
{
|
|
845
|
+
// Insert + Delete
|
|
846
|
+
//
|
|
847
|
+
// All operations are no-ops (& i remains the same)
|
|
848
|
+
|
|
849
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
850
|
+
[changes removeObjectAtIndex:i];
|
|
851
|
+
|
|
852
|
+
}
|
|
853
|
+
else if (lastChangeForKey->type == YapDatabaseViewChangeInsert)
|
|
854
|
+
{
|
|
855
|
+
// Insert + Delete + ... + Insert
|
|
856
|
+
//
|
|
857
|
+
// All operations except the last are no-ops.
|
|
858
|
+
|
|
859
|
+
firstChangeForKey->finalIndex = lastChangeForKey->finalIndex;
|
|
860
|
+
firstChangeForKey->finalGroup = lastChangeForKey->finalGroup;
|
|
861
|
+
|
|
862
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
863
|
+
i++;
|
|
864
|
+
}
|
|
865
|
+
else // if (lastChangeForKey->type == YapDatabaseViewChangeUpdate)
|
|
866
|
+
{
|
|
867
|
+
// Insert + Update
|
|
868
|
+
//
|
|
869
|
+
// This is still an insert, but the final location may have changed.
|
|
870
|
+
|
|
871
|
+
firstChangeForKey->finalIndex = lastChangeForKey->finalIndex;
|
|
872
|
+
firstChangeForKey->finalGroup = lastChangeForKey->finalGroup;
|
|
873
|
+
|
|
874
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
875
|
+
i++;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
else if (firstChangeForKey->type == YapDatabaseViewChangeUpdate)
|
|
879
|
+
{
|
|
880
|
+
if (lastChangeForKey->type == YapDatabaseViewChangeDelete)
|
|
881
|
+
{
|
|
882
|
+
// Update + Delete
|
|
883
|
+
//
|
|
884
|
+
// This is ultimately a Delete.
|
|
885
|
+
// We need to be sure to use the original original index.
|
|
886
|
+
|
|
887
|
+
firstChangeForKey->type = YapDatabaseViewChangeDelete;
|
|
888
|
+
|
|
889
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
890
|
+
i++;
|
|
891
|
+
}
|
|
892
|
+
else if (lastChangeForKey->type == YapDatabaseViewChangeInsert)
|
|
893
|
+
{
|
|
894
|
+
// Update + Delete + ... + Insert = Move
|
|
895
|
+
//
|
|
896
|
+
// This is always a move operation.
|
|
897
|
+
// Even if the final location hasn't ultimately changed, we still want to treat it as a move.
|
|
898
|
+
// Only a true update, where the index never budged, can be emitted as an update.
|
|
899
|
+
//
|
|
900
|
+
// If we attempt to consolidate this into an update,
|
|
901
|
+
// then the tableView/collectionView will offset the update's index
|
|
902
|
+
// based on insertions & deletions at smaller indexes,
|
|
903
|
+
// and may ultimately update the wrong cell.
|
|
904
|
+
|
|
905
|
+
firstChangeForKey->type = YapDatabaseViewChangeMove;
|
|
906
|
+
firstChangeForKey->finalIndex = lastChangeForKey->finalIndex;
|
|
907
|
+
firstChangeForKey->finalGroup = lastChangeForKey->finalGroup;
|
|
908
|
+
|
|
909
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
910
|
+
i++;
|
|
911
|
+
}
|
|
912
|
+
else // if (lastChangeForKey->type == YapDatabaseViewChangeUpdate)
|
|
913
|
+
{
|
|
914
|
+
// Update + ... + Update
|
|
915
|
+
//
|
|
916
|
+
// This is either an Update or a Move.
|
|
917
|
+
// Only a true update, where the index never budged, can be emitted as an update.
|
|
918
|
+
//
|
|
919
|
+
// So we scan all the changes, and if every single one is an update, then we can emit an update.
|
|
920
|
+
|
|
921
|
+
__block BOOL isTrueUpdate = YES;
|
|
922
|
+
|
|
923
|
+
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
|
924
|
+
|
|
925
|
+
YapDatabaseViewRowChange *changeForKey = [changes objectAtIndex:idx];
|
|
926
|
+
|
|
927
|
+
if (changeForKey->type != YapDatabaseViewChangeUpdate)
|
|
928
|
+
{
|
|
929
|
+
isTrueUpdate = NO;
|
|
930
|
+
*stop = YES;
|
|
931
|
+
}
|
|
932
|
+
}];
|
|
933
|
+
|
|
934
|
+
if (isTrueUpdate)
|
|
935
|
+
{
|
|
936
|
+
// = Update
|
|
937
|
+
|
|
938
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
939
|
+
i++;
|
|
940
|
+
}
|
|
941
|
+
else
|
|
942
|
+
{
|
|
943
|
+
// = Move
|
|
944
|
+
//
|
|
945
|
+
// The final location comes from the last update
|
|
946
|
+
|
|
947
|
+
firstChangeForKey->type = YapDatabaseViewChangeMove;
|
|
948
|
+
firstChangeForKey->finalIndex = lastChangeForKey->finalIndex;
|
|
949
|
+
firstChangeForKey->finalGroup = lastChangeForKey->finalGroup;
|
|
950
|
+
|
|
951
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
952
|
+
i++;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
[indexSet removeAllIndexes];
|
|
958
|
+
|
|
959
|
+
} // ([indexSet count] > 0)
|
|
960
|
+
|
|
961
|
+
} // while (i < [changes count])
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* This method consolidates multiple changes to the same section into a single change.
|
|
966
|
+
**/
|
|
967
|
+
+ (void)consolidateSectionChanges:(NSMutableArray *)changes
|
|
968
|
+
{
|
|
969
|
+
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
|
|
970
|
+
|
|
971
|
+
NSUInteger i = 0;
|
|
972
|
+
while (i < [changes count])
|
|
973
|
+
{
|
|
974
|
+
YapDatabaseViewSectionChange *firstSectionChangeForGroup = [changes objectAtIndex:i];
|
|
975
|
+
|
|
976
|
+
// Find later operations with the same group
|
|
977
|
+
|
|
978
|
+
for (NSUInteger j = i+1; j < [changes count]; j++)
|
|
979
|
+
{
|
|
980
|
+
YapDatabaseViewSectionChange *laterSectionChange = [changes objectAtIndex:j];
|
|
981
|
+
|
|
982
|
+
if ([laterSectionChange->group isEqualToString:firstSectionChangeForGroup->group])
|
|
983
|
+
{
|
|
984
|
+
[indexSet addIndex:j];
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if ([indexSet count] == 0)
|
|
989
|
+
{
|
|
990
|
+
i++;
|
|
991
|
+
}
|
|
992
|
+
else
|
|
993
|
+
{
|
|
994
|
+
YapDatabaseViewSectionChange *lastSectionChangeForGroup = [changes objectAtIndex:[indexSet lastIndex]];
|
|
995
|
+
|
|
996
|
+
if (firstSectionChangeForGroup->type == YapDatabaseViewChangeDelete)
|
|
997
|
+
{
|
|
998
|
+
if (lastSectionChangeForGroup->type == YapDatabaseViewChangeDelete)
|
|
999
|
+
{
|
|
1000
|
+
// Delete + Insert + ... + Delete
|
|
1001
|
+
//
|
|
1002
|
+
// All operations except the first are no-ops
|
|
1003
|
+
|
|
1004
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
1005
|
+
i++;
|
|
1006
|
+
}
|
|
1007
|
+
else // if (lastSectionChangeForGroup->type == YapDatabaseViewChangeInsert)
|
|
1008
|
+
{
|
|
1009
|
+
// Delete + Insert
|
|
1010
|
+
//
|
|
1011
|
+
// All operations are no-ops (& i remains the same)
|
|
1012
|
+
|
|
1013
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
1014
|
+
[changes removeObjectAtIndex:i];
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
else if (firstSectionChangeForGroup->type == YapDatabaseViewChangeInsert)
|
|
1018
|
+
{
|
|
1019
|
+
if (lastSectionChangeForGroup->type == YapDatabaseViewChangeDelete)
|
|
1020
|
+
{
|
|
1021
|
+
// Insert + Delete
|
|
1022
|
+
//
|
|
1023
|
+
// All operations are no-ops (& i remains the same)
|
|
1024
|
+
|
|
1025
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
1026
|
+
[changes removeObjectAtIndex:i];
|
|
1027
|
+
}
|
|
1028
|
+
else if (lastSectionChangeForGroup->type == YapDatabaseViewChangeInsert)
|
|
1029
|
+
{
|
|
1030
|
+
// Insert + Delete + ... + Insert
|
|
1031
|
+
//
|
|
1032
|
+
// All operations except the first are no-ops.
|
|
1033
|
+
|
|
1034
|
+
[changes removeObjectsAtIndexes:indexSet];
|
|
1035
|
+
i++;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* This method applies the given mappings to the processed list of row changes.
|
|
1044
|
+
* Based upon the configuration of the mappings, it will
|
|
1045
|
+
*
|
|
1046
|
+
* - filter items that are excluded based on per-group range configurations
|
|
1047
|
+
* - alter indexes based on per-group range configurations
|
|
1048
|
+
* - reverse indexes based on per-group reversal settings
|
|
1049
|
+
**/
|
|
1050
|
+
+ (void)postProcessAndFilterRowChanges:(NSMutableArray *)rowChanges
|
|
1051
|
+
withOriginalMappings:(YapDatabaseViewMappings *)originalMappings
|
|
1052
|
+
finalMappings:(YapDatabaseViewMappings *)finalMappings
|
|
1053
|
+
{
|
|
1054
|
+
|
|
1055
|
+
// The user may have various range options set for each section/group.
|
|
1056
|
+
// For example:
|
|
1057
|
+
//
|
|
1058
|
+
// The user has a hard range on group "fiction" in the "bookSalesRank" view in order to display the top 20.
|
|
1059
|
+
// So any items outside of that range must be filtered.
|
|
1060
|
+
|
|
1061
|
+
NSDictionary *rangeOptions = [finalMappings rangeOptions];
|
|
1062
|
+
BOOL rangeOptionsChanged = YES;
|
|
1063
|
+
|
|
1064
|
+
// Note: The rangeOptions are the same between originalMappings & finalMappings.
|
|
1065
|
+
|
|
1066
|
+
for (NSString *group in rangeOptions)
|
|
1067
|
+
{
|
|
1068
|
+
YapDatabaseViewRangeOptions *rangeOpts = [rangeOptions objectForKey:group];
|
|
1069
|
+
|
|
1070
|
+
NSUInteger originalGroupCount = [originalMappings fullCountForGroup:group];
|
|
1071
|
+
NSUInteger finalGroupCount = [finalMappings fullCountForGroup:group];
|
|
1072
|
+
|
|
1073
|
+
YapDatabaseViewPin pin = rangeOpts.pin;
|
|
1074
|
+
|
|
1075
|
+
//
|
|
1076
|
+
// STEP 1 : Calculate the originalRange & finalRange
|
|
1077
|
+
//
|
|
1078
|
+
|
|
1079
|
+
NSUInteger originalRangeLength = rangeOpts.length;
|
|
1080
|
+
NSUInteger originalRangeOffset = rangeOpts.offset;
|
|
1081
|
+
|
|
1082
|
+
NSUInteger originalRangeMin;
|
|
1083
|
+
NSUInteger originalRangeMax;
|
|
1084
|
+
|
|
1085
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1086
|
+
{
|
|
1087
|
+
originalRangeMin = originalRangeOffset;
|
|
1088
|
+
originalRangeMax = originalRangeOffset + originalRangeLength;
|
|
1089
|
+
}
|
|
1090
|
+
else // if (pin == YapDatabaseViewEnd)
|
|
1091
|
+
{
|
|
1092
|
+
if (originalRangeOffset < originalGroupCount) {
|
|
1093
|
+
originalRangeMax = originalGroupCount - originalRangeOffset;
|
|
1094
|
+
originalRangeMin = originalRangeMax - originalRangeLength;
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
originalRangeMax = 0;
|
|
1098
|
+
originalRangeMin = 0;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
NSUInteger finalRangeLength;
|
|
1103
|
+
NSUInteger finalRangeOffset;
|
|
1104
|
+
|
|
1105
|
+
NSUInteger finalRangeMin;
|
|
1106
|
+
NSUInteger finalRangeMax;
|
|
1107
|
+
|
|
1108
|
+
NSUInteger flexibleRangeNonPinSideDeleteDiff = 0;
|
|
1109
|
+
NSUInteger flexibleRangePinSideInsertDiff = 0;
|
|
1110
|
+
NSUInteger flexibleRangeNonPinSideInsertDiff = 0;
|
|
1111
|
+
|
|
1112
|
+
if (rangeOpts.isFixedRange)
|
|
1113
|
+
{
|
|
1114
|
+
// FIXED Range:
|
|
1115
|
+
//
|
|
1116
|
+
// - The length is fixed. It only shrinks if we run out of keys.
|
|
1117
|
+
// - The offset never changes.
|
|
1118
|
+
//
|
|
1119
|
+
// If pinned to the BEGINNING:
|
|
1120
|
+
// The offset represents how far the beginning of the range is from the beginning of the group.
|
|
1121
|
+
//
|
|
1122
|
+
// Group : <---------------------------------------->
|
|
1123
|
+
// Range : <--------->
|
|
1124
|
+
// Offset: <----------------> (pin == YapDatabaseViewBeginning)
|
|
1125
|
+
//
|
|
1126
|
+
// If pinned to the END:
|
|
1127
|
+
// The offset represents how far the end of the range is from the end of the group.
|
|
1128
|
+
//
|
|
1129
|
+
// Group : <---------------------------------------->
|
|
1130
|
+
// Range : <--------->
|
|
1131
|
+
// Offset: <-------------> (pin == YapDatabaseViewEnd)
|
|
1132
|
+
|
|
1133
|
+
finalRangeOffset = originalRangeOffset;
|
|
1134
|
+
|
|
1135
|
+
NSUInteger maxFinalRangeLength;
|
|
1136
|
+
if (finalGroupCount > finalRangeOffset)
|
|
1137
|
+
maxFinalRangeLength = finalGroupCount - finalRangeOffset;
|
|
1138
|
+
else
|
|
1139
|
+
maxFinalRangeLength = 0;
|
|
1140
|
+
|
|
1141
|
+
finalRangeLength = MIN(rangeOpts.maxLength, maxFinalRangeLength);
|
|
1142
|
+
|
|
1143
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1144
|
+
{
|
|
1145
|
+
finalRangeMin = finalRangeOffset;
|
|
1146
|
+
finalRangeMax = finalRangeOffset + finalRangeLength;
|
|
1147
|
+
}
|
|
1148
|
+
else // if (pin == YapDatabaseViewEnd)
|
|
1149
|
+
{
|
|
1150
|
+
if (finalRangeOffset < finalGroupCount) {
|
|
1151
|
+
finalRangeMax = finalGroupCount - finalRangeOffset;
|
|
1152
|
+
finalRangeMin = finalRangeMax - finalRangeLength;
|
|
1153
|
+
}
|
|
1154
|
+
else {
|
|
1155
|
+
finalRangeMax = 0;
|
|
1156
|
+
finalRangeMin = 0;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
else // if (rangeOpts.isFlexibleRange)
|
|
1161
|
+
{
|
|
1162
|
+
// FLEXIBLE Range:
|
|
1163
|
+
//
|
|
1164
|
+
// The length changes as items are inserted and deleted with the range boundary.
|
|
1165
|
+
// The offset changes as items are inserted and deleted between the range and its pinned end.
|
|
1166
|
+
|
|
1167
|
+
finalRangeMin = originalRangeMin;
|
|
1168
|
+
finalRangeMax = originalRangeMax;
|
|
1169
|
+
|
|
1170
|
+
BOOL finalRangeWasEmpty = ((finalRangeMax - finalRangeMin) == 0);
|
|
1171
|
+
|
|
1172
|
+
YapDatabaseViewGrowOptions growOptions = rangeOpts.growOptions;
|
|
1173
|
+
|
|
1174
|
+
for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1175
|
+
{
|
|
1176
|
+
if (rowChange->type == YapDatabaseViewChangeDelete || rowChange->type == YapDatabaseViewChangeMove)
|
|
1177
|
+
{
|
|
1178
|
+
if ([rowChange->originalGroup isEqualToString:group])
|
|
1179
|
+
{
|
|
1180
|
+
// A DELETE operation can:
|
|
1181
|
+
// - decrement the location of the final range
|
|
1182
|
+
// - decrease the length of the final range
|
|
1183
|
+
|
|
1184
|
+
if (rowChange->opOriginalIndex < finalRangeMin)
|
|
1185
|
+
{
|
|
1186
|
+
finalRangeMin -= 1;
|
|
1187
|
+
}
|
|
1188
|
+
if (rowChange->opOriginalIndex < finalRangeMax)
|
|
1189
|
+
{
|
|
1190
|
+
finalRangeMax -= 1;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
}// fi (rowChange->type == YapDatabaseViewChangeDelete || rowChange->type == YapDatabaseViewChangeMove)
|
|
1195
|
+
|
|
1196
|
+
if (rowChange->type == YapDatabaseViewChangeInsert || rowChange->type == YapDatabaseViewChangeMove)
|
|
1197
|
+
{
|
|
1198
|
+
if ([rowChange->finalGroup isEqualToString:group])
|
|
1199
|
+
{
|
|
1200
|
+
// An INSERT operation can:
|
|
1201
|
+
// - increment the location of the final range
|
|
1202
|
+
// - increase the length of the final range
|
|
1203
|
+
//
|
|
1204
|
+
// How do we know if an inserted item should be included in the range?
|
|
1205
|
+
// This is based upon the growOptions.
|
|
1206
|
+
//
|
|
1207
|
+
// Please see the documentation in the header file for the growOptions property.
|
|
1208
|
+
// It has an extended discussion.
|
|
1209
|
+
|
|
1210
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1211
|
+
{
|
|
1212
|
+
if ((growOptions & YapDatabaseViewGrowPinSide) || finalRangeWasEmpty)
|
|
1213
|
+
{
|
|
1214
|
+
if (rowChange->opFinalIndex < finalRangeMin)
|
|
1215
|
+
finalRangeMin++;
|
|
1216
|
+
}
|
|
1217
|
+
else
|
|
1218
|
+
{
|
|
1219
|
+
if (rowChange->opFinalIndex <= finalRangeMin)
|
|
1220
|
+
finalRangeMin++;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
if ((growOptions & YapDatabaseViewGrowNonPinSide) || finalRangeWasEmpty)
|
|
1224
|
+
{
|
|
1225
|
+
if (rowChange->opFinalIndex <= finalRangeMax)
|
|
1226
|
+
finalRangeMax++;
|
|
1227
|
+
}
|
|
1228
|
+
else
|
|
1229
|
+
{
|
|
1230
|
+
if (rowChange->opFinalIndex < finalRangeMax)
|
|
1231
|
+
finalRangeMax++;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
else // if (pin == YapDatabaseViewEnd)
|
|
1235
|
+
{
|
|
1236
|
+
if ((growOptions & YapDatabaseViewGrowNonPinSide) || finalRangeWasEmpty)
|
|
1237
|
+
{
|
|
1238
|
+
if (rowChange->opFinalIndex < finalRangeMin)
|
|
1239
|
+
finalRangeMin++;
|
|
1240
|
+
}
|
|
1241
|
+
else
|
|
1242
|
+
{
|
|
1243
|
+
if (rowChange->opFinalIndex <= finalRangeMin)
|
|
1244
|
+
finalRangeMin++;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
if ((growOptions & YapDatabaseViewGrowPinSide) || finalRangeWasEmpty)
|
|
1248
|
+
{
|
|
1249
|
+
if (rowChange->opFinalIndex <= finalRangeMax)
|
|
1250
|
+
finalRangeMax++;
|
|
1251
|
+
}
|
|
1252
|
+
else
|
|
1253
|
+
{
|
|
1254
|
+
if (rowChange->opFinalIndex < finalRangeMax)
|
|
1255
|
+
finalRangeMax++;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
}// fi (rowChange->type == YapDatabaseViewChangeInsert || rowChange->type == YapDatabaseViewChangeMove)
|
|
1261
|
+
|
|
1262
|
+
// If the range ever becomes empty,
|
|
1263
|
+
// then we need to effectively set the growOptions to YapDatabaseViewGrowOnBothSides.
|
|
1264
|
+
//
|
|
1265
|
+
// With an empty range, there is no different between PinSide and NonPinSide.
|
|
1266
|
+
//
|
|
1267
|
+
// Notice that this flag, once set, remains set.
|
|
1268
|
+
|
|
1269
|
+
finalRangeWasEmpty = finalRangeWasEmpty || ((finalRangeMax - finalRangeMin) == 0);
|
|
1270
|
+
|
|
1271
|
+
} // end for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
// Adjust if we exceed max length, or drop below min length
|
|
1275
|
+
|
|
1276
|
+
finalRangeLength = finalRangeMax - finalRangeMin;
|
|
1277
|
+
|
|
1278
|
+
if (finalRangeLength > rangeOpts.maxLength)
|
|
1279
|
+
{
|
|
1280
|
+
NSUInteger diff = finalRangeLength - rangeOpts.maxLength;
|
|
1281
|
+
flexibleRangeNonPinSideDeleteDiff = diff;
|
|
1282
|
+
|
|
1283
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1284
|
+
{
|
|
1285
|
+
// Prune from non-pin-side (end)
|
|
1286
|
+
finalRangeMax -= diff;
|
|
1287
|
+
}
|
|
1288
|
+
else // if (pin == YapDatabaseViewEnd)
|
|
1289
|
+
{
|
|
1290
|
+
// Prune from non-pin-side (beginning)
|
|
1291
|
+
finalRangeMin += diff;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
}
|
|
1295
|
+
else if ((finalRangeLength < rangeOpts.minLength) && (finalRangeLength < finalGroupCount))
|
|
1296
|
+
{
|
|
1297
|
+
NSUInteger diff = rangeOpts.minLength - finalRangeLength;
|
|
1298
|
+
|
|
1299
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1300
|
+
{
|
|
1301
|
+
// Append from pin-side first (beginning) (if possible)
|
|
1302
|
+
if (finalRangeMin > 0)
|
|
1303
|
+
{
|
|
1304
|
+
NSUInteger pinSideDiff = MIN(diff, finalRangeMin);
|
|
1305
|
+
flexibleRangePinSideInsertDiff = pinSideDiff;
|
|
1306
|
+
|
|
1307
|
+
finalRangeMin -= pinSideDiff;
|
|
1308
|
+
diff -= pinSideDiff;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// Append from non-pin-side second (end) (if possible) (if still needed)
|
|
1312
|
+
if ((finalRangeMax < finalGroupCount) && (diff > 0))
|
|
1313
|
+
{
|
|
1314
|
+
NSUInteger nonPinSideDiff = MIN(diff, (finalGroupCount - finalRangeMax));
|
|
1315
|
+
flexibleRangeNonPinSideInsertDiff = nonPinSideDiff;
|
|
1316
|
+
|
|
1317
|
+
finalRangeMax += nonPinSideDiff;
|
|
1318
|
+
//diff -= nonPinSideDiff;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
else // if (pin == YapDatabaseViewEnd)
|
|
1322
|
+
{
|
|
1323
|
+
// Append from pin-side first (end) (if possible)
|
|
1324
|
+
if (finalRangeMax < finalGroupCount)
|
|
1325
|
+
{
|
|
1326
|
+
NSUInteger pinSideDiff = MIN(diff, (finalGroupCount - finalRangeMax));
|
|
1327
|
+
flexibleRangePinSideInsertDiff = pinSideDiff;
|
|
1328
|
+
|
|
1329
|
+
finalRangeMax += pinSideDiff;
|
|
1330
|
+
diff -= pinSideDiff;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// Append from non-pin-side second (beginning) (if possible) (if still needed)
|
|
1334
|
+
if ((finalRangeMin > 0) && (diff > 0))
|
|
1335
|
+
{
|
|
1336
|
+
NSUInteger nonPinSideDiff = MIN(diff, finalRangeMin);
|
|
1337
|
+
flexibleRangeNonPinSideInsertDiff = nonPinSideDiff;
|
|
1338
|
+
|
|
1339
|
+
finalRangeMin -= nonPinSideDiff;
|
|
1340
|
+
//diff -= nonPinSideDiff;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// Set finalLength & finalOffset
|
|
1346
|
+
|
|
1347
|
+
finalRangeLength = finalRangeMax - finalRangeMin;
|
|
1348
|
+
|
|
1349
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1350
|
+
finalRangeOffset = finalRangeMin;
|
|
1351
|
+
else
|
|
1352
|
+
finalRangeOffset = finalGroupCount - finalRangeMax;
|
|
1353
|
+
|
|
1354
|
+
} // END if (rangeOpts.isFlexibleRange)
|
|
1355
|
+
|
|
1356
|
+
//
|
|
1357
|
+
// STEP 2 : Filter items that are outside the range, and "map" items that are inside the range.
|
|
1358
|
+
//
|
|
1359
|
+
// By "map" we mean update the index to match the range, not the entire view.
|
|
1360
|
+
// For example, if there is a hard range to display only the last 20 items in the view,
|
|
1361
|
+
// then the index of the last item should be 20 (range.length), not 436 (group.length).
|
|
1362
|
+
|
|
1363
|
+
NSUInteger deleteCount = 0;
|
|
1364
|
+
NSUInteger insertCount = 0;
|
|
1365
|
+
|
|
1366
|
+
NSUInteger i = 0;
|
|
1367
|
+
while (i < [rowChanges count])
|
|
1368
|
+
{
|
|
1369
|
+
YapDatabaseViewRowChange *rowChange = [rowChanges objectAtIndex:i];
|
|
1370
|
+
|
|
1371
|
+
if (rowChange->type == YapDatabaseViewChangeDelete)
|
|
1372
|
+
{
|
|
1373
|
+
if ([rowChange->originalGroup isEqualToString:group])
|
|
1374
|
+
{
|
|
1375
|
+
if (rowChange->originalIndex >= originalRangeMin &&
|
|
1376
|
+
rowChange->originalIndex < originalRangeMax)
|
|
1377
|
+
{
|
|
1378
|
+
// Include in changeset
|
|
1379
|
+
i++;
|
|
1380
|
+
deleteCount++;
|
|
1381
|
+
|
|
1382
|
+
// Update index to match range
|
|
1383
|
+
rowChange->originalIndex -= originalRangeMin;
|
|
1384
|
+
}
|
|
1385
|
+
else
|
|
1386
|
+
{
|
|
1387
|
+
// Exclude from changeset
|
|
1388
|
+
[rowChanges removeObjectAtIndex:i];
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
else if (rowChange->type == YapDatabaseViewChangeInsert)
|
|
1393
|
+
{
|
|
1394
|
+
if ([rowChange->finalGroup isEqualToString:group])
|
|
1395
|
+
{
|
|
1396
|
+
if (rowChange->finalIndex >= finalRangeMin &&
|
|
1397
|
+
rowChange->finalIndex < finalRangeMax)
|
|
1398
|
+
{
|
|
1399
|
+
// Include in changeset
|
|
1400
|
+
i++;
|
|
1401
|
+
insertCount++;
|
|
1402
|
+
|
|
1403
|
+
// Update index to match range
|
|
1404
|
+
rowChange->finalIndex -= finalRangeMin;
|
|
1405
|
+
}
|
|
1406
|
+
else
|
|
1407
|
+
{
|
|
1408
|
+
// Exclude from changeset
|
|
1409
|
+
[rowChanges removeObjectAtIndex:i];
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
1414
|
+
{
|
|
1415
|
+
if ([rowChange->originalGroup isEqualToString:group])
|
|
1416
|
+
{
|
|
1417
|
+
if (rowChange->originalIndex >= originalRangeMin &&
|
|
1418
|
+
rowChange->originalIndex < originalRangeMax)
|
|
1419
|
+
{
|
|
1420
|
+
// Include in changeset
|
|
1421
|
+
i++;
|
|
1422
|
+
|
|
1423
|
+
// Update index to match range
|
|
1424
|
+
rowChange->originalIndex -= originalRangeMin;
|
|
1425
|
+
rowChange->finalIndex -= finalRangeMin;
|
|
1426
|
+
}
|
|
1427
|
+
else
|
|
1428
|
+
{
|
|
1429
|
+
// Exclude from changeset
|
|
1430
|
+
[rowChanges removeObjectAtIndex:i];
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
else if (rowChange->type == YapDatabaseViewChangeMove)
|
|
1435
|
+
{
|
|
1436
|
+
// A move is both a delete and an insert.
|
|
1437
|
+
// Sometimes both operations apply to this group.
|
|
1438
|
+
// Sometimes only one.
|
|
1439
|
+
// Sometimes neither.
|
|
1440
|
+
|
|
1441
|
+
BOOL filterDelete = NO;
|
|
1442
|
+
BOOL filterInsert = NO;
|
|
1443
|
+
|
|
1444
|
+
if ([rowChange->originalGroup isEqualToString:group])
|
|
1445
|
+
{
|
|
1446
|
+
if (rowChange->originalIndex >= originalRangeMin &&
|
|
1447
|
+
rowChange->originalIndex < originalRangeMax)
|
|
1448
|
+
{
|
|
1449
|
+
// Include (delete operation) in changeset
|
|
1450
|
+
|
|
1451
|
+
// Update index to match range
|
|
1452
|
+
rowChange->originalIndex -= originalRangeMin;
|
|
1453
|
+
}
|
|
1454
|
+
else
|
|
1455
|
+
{
|
|
1456
|
+
// Exclude (delete operation) from changeset
|
|
1457
|
+
filterDelete = YES;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
if ([rowChange->finalGroup isEqualToString:group])
|
|
1462
|
+
{
|
|
1463
|
+
if (rowChange->finalIndex >= finalRangeMin &&
|
|
1464
|
+
rowChange->finalIndex < finalRangeMax)
|
|
1465
|
+
{
|
|
1466
|
+
// Include (insert operation) in changeset
|
|
1467
|
+
|
|
1468
|
+
// Update index to match range
|
|
1469
|
+
rowChange->finalIndex -= finalRangeMin;
|
|
1470
|
+
}
|
|
1471
|
+
else
|
|
1472
|
+
{
|
|
1473
|
+
// Exclude (insert operation) from changeset
|
|
1474
|
+
filterInsert = YES;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
if (filterDelete && filterInsert)
|
|
1479
|
+
{
|
|
1480
|
+
// Exclude from changeset
|
|
1481
|
+
[rowChanges removeObjectAtIndex:i];
|
|
1482
|
+
}
|
|
1483
|
+
else if (filterDelete && !filterInsert)
|
|
1484
|
+
{
|
|
1485
|
+
// Move -> Insert
|
|
1486
|
+
rowChange->type = YapDatabaseViewChangeInsert;
|
|
1487
|
+
i++;
|
|
1488
|
+
insertCount++;
|
|
1489
|
+
}
|
|
1490
|
+
else if (!filterDelete && filterInsert)
|
|
1491
|
+
{
|
|
1492
|
+
// Move -> Delete
|
|
1493
|
+
rowChange->type = YapDatabaseViewChangeDelete;
|
|
1494
|
+
i++;
|
|
1495
|
+
deleteCount++;
|
|
1496
|
+
}
|
|
1497
|
+
else
|
|
1498
|
+
{
|
|
1499
|
+
// Move
|
|
1500
|
+
i++;
|
|
1501
|
+
insertCount++;
|
|
1502
|
+
deleteCount++;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
//
|
|
1508
|
+
// STEP 3: Fix the final counts by manually adding any needed insertions or deletions
|
|
1509
|
+
//
|
|
1510
|
+
|
|
1511
|
+
NSUInteger numberOfInsertOperationsToManuallyAdd = 0;
|
|
1512
|
+
NSUInteger numberOfDeleteOperationsToManuallyAdd = 0;
|
|
1513
|
+
|
|
1514
|
+
if (rangeOpts.isFixedRange)
|
|
1515
|
+
{
|
|
1516
|
+
// FIXED Range:
|
|
1517
|
+
//
|
|
1518
|
+
// For fixed ranges, we need to ensure the changeset reflects the proper count.
|
|
1519
|
+
// For example:
|
|
1520
|
+
//
|
|
1521
|
+
// The fixed range has a lenth of 20.
|
|
1522
|
+
// The only changes were 2 insertions.
|
|
1523
|
+
// Thus, we need to add 2 delete changes to balance the length.
|
|
1524
|
+
//
|
|
1525
|
+
// These represent the items that got pushed out of the range.
|
|
1526
|
+
|
|
1527
|
+
NSUInteger length = originalRangeLength;
|
|
1528
|
+
length += insertCount;
|
|
1529
|
+
length -= deleteCount;
|
|
1530
|
+
|
|
1531
|
+
if (length > finalRangeLength)
|
|
1532
|
+
{
|
|
1533
|
+
// Need to add DELETE operations.
|
|
1534
|
+
|
|
1535
|
+
numberOfDeleteOperationsToManuallyAdd = length - finalRangeLength;
|
|
1536
|
+
}
|
|
1537
|
+
else if (length < finalRangeLength)
|
|
1538
|
+
{
|
|
1539
|
+
// Need to add INSERT operations.
|
|
1540
|
+
|
|
1541
|
+
numberOfInsertOperationsToManuallyAdd = finalRangeLength - length;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
else if (flexibleRangeNonPinSideDeleteDiff != 0)
|
|
1545
|
+
{
|
|
1546
|
+
// FLEXIBLE Range:
|
|
1547
|
+
//
|
|
1548
|
+
// The range naturally expanded to the point where it exceeded the max length.
|
|
1549
|
+
// We may need to manually add DELETE operations.
|
|
1550
|
+
|
|
1551
|
+
NSInteger expectedDiff = finalRangeLength - originalRangeLength;
|
|
1552
|
+
NSInteger actualDiff = insertCount - deleteCount;
|
|
1553
|
+
|
|
1554
|
+
// Example 1: typical length going above max
|
|
1555
|
+
//
|
|
1556
|
+
// originalRangeLength = 5, finalRangeLength = 10, max = 10, insertCount = 10, deleteCount = 0
|
|
1557
|
+
// expectedDiff = 5
|
|
1558
|
+
// actualDiff = 10
|
|
1559
|
+
|
|
1560
|
+
// Example 2: user changed max value on us without changing length
|
|
1561
|
+
// (not technically supporeted, but not overly difficult to handle)
|
|
1562
|
+
//
|
|
1563
|
+
// originalRangeLength = 10, finalRangeLength = 5, max = 5, insertCount = 1, deleteCount = 0
|
|
1564
|
+
// expectedDiff = -5
|
|
1565
|
+
// actualDiff = 1
|
|
1566
|
+
|
|
1567
|
+
if (actualDiff > expectedDiff)
|
|
1568
|
+
{
|
|
1569
|
+
numberOfDeleteOperationsToManuallyAdd = actualDiff - expectedDiff;
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
else if ((flexibleRangePinSideInsertDiff > 0) || (flexibleRangeNonPinSideInsertDiff > 0))
|
|
1573
|
+
{
|
|
1574
|
+
// FLEXIBLE Range:
|
|
1575
|
+
//
|
|
1576
|
+
// The range naturally shrunk to the point where it was smaller than the min length.
|
|
1577
|
+
// We may need to manually add INSERT operations.
|
|
1578
|
+
//
|
|
1579
|
+
// Note: The originalRangeLength may actually be smaller than the finalRangeLength.
|
|
1580
|
+
|
|
1581
|
+
NSInteger expectedDiff = finalRangeLength - originalRangeLength;
|
|
1582
|
+
NSInteger actualDiff = insertCount - deleteCount;
|
|
1583
|
+
|
|
1584
|
+
// Example 1: database near empty to begin with
|
|
1585
|
+
//
|
|
1586
|
+
// originalRangeLength = 1, finalRangeLength = 5, min = 5, insertCount = 5, deleteCount = 1
|
|
1587
|
+
// expectedDiff = 4
|
|
1588
|
+
// actualDiff = 4
|
|
1589
|
+
|
|
1590
|
+
// Example 2: typical length dropping below min
|
|
1591
|
+
//
|
|
1592
|
+
// originalRangeLength = 5, finalRangeLength = 5, min = 5, insertCount = 0, deleteCount = 2
|
|
1593
|
+
// expectedDiff = 0
|
|
1594
|
+
// actualDiff = -2
|
|
1595
|
+
|
|
1596
|
+
// Example 3: typical length dropping below min
|
|
1597
|
+
//
|
|
1598
|
+
// originalRangeLength = 10, finalRangeLength = 5, min = 5, insertCount = 0, deleteCount = 8
|
|
1599
|
+
// expectedDiff = -5
|
|
1600
|
+
// actualDiff = -8
|
|
1601
|
+
|
|
1602
|
+
// Example 4: user changed min value on us without changing length
|
|
1603
|
+
// (not technically supported, but not overly difficult to handle)
|
|
1604
|
+
//
|
|
1605
|
+
// originalRangeLength = 2, finalRangeLength = 5, min = 5, insertCount = 2, deleteCount = 0
|
|
1606
|
+
// expectedDiff = 3
|
|
1607
|
+
// actualDiff = 2
|
|
1608
|
+
|
|
1609
|
+
if (actualDiff < expectedDiff)
|
|
1610
|
+
{
|
|
1611
|
+
numberOfInsertOperationsToManuallyAdd = expectedDiff - actualDiff;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
if (numberOfDeleteOperationsToManuallyAdd > 0)
|
|
1616
|
+
{
|
|
1617
|
+
// Manually add DELETE operations.
|
|
1618
|
+
//
|
|
1619
|
+
// These operations represent the objects that got pushed out of the final range,
|
|
1620
|
+
// even though the items themselves didn't change.
|
|
1621
|
+
//
|
|
1622
|
+
// They are to go at the end opposite the pin.
|
|
1623
|
+
|
|
1624
|
+
NSUInteger count = 0;
|
|
1625
|
+
|
|
1626
|
+
NSUInteger index;
|
|
1627
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1628
|
+
index = originalRangeLength - 1;
|
|
1629
|
+
else
|
|
1630
|
+
index = 0;
|
|
1631
|
+
|
|
1632
|
+
while (count < numberOfDeleteOperationsToManuallyAdd)
|
|
1633
|
+
{
|
|
1634
|
+
// We need to be careful not to step on existing rowChanges.
|
|
1635
|
+
// If there is an existing delete for this index, we need to continue onto the next index.
|
|
1636
|
+
// If there is an existing move from this index, we need to continue onto the next index.
|
|
1637
|
+
// If there is an existing update for this index, we need to change it to a delete.
|
|
1638
|
+
|
|
1639
|
+
BOOL found = NO;
|
|
1640
|
+
|
|
1641
|
+
for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1642
|
+
{
|
|
1643
|
+
if (rowChange->type == YapDatabaseViewChangeDelete ||
|
|
1644
|
+
rowChange->type == YapDatabaseViewChangeMove)
|
|
1645
|
+
{
|
|
1646
|
+
if (rowChange->originalIndex == index && [rowChange->originalGroup isEqualToString:group])
|
|
1647
|
+
{
|
|
1648
|
+
found = YES;
|
|
1649
|
+
break;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
1653
|
+
{
|
|
1654
|
+
if (rowChange->originalIndex == index && [rowChange->originalGroup isEqualToString:group])
|
|
1655
|
+
{
|
|
1656
|
+
rowChange->type = YapDatabaseViewChangeDelete;
|
|
1657
|
+
|
|
1658
|
+
count++;
|
|
1659
|
+
found = YES;
|
|
1660
|
+
break;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
if (!found)
|
|
1666
|
+
{
|
|
1667
|
+
YapDatabaseViewRowChange *rowChange =
|
|
1668
|
+
[YapDatabaseViewRowChange deleteKey:nil inGroup:group atIndex:index];
|
|
1669
|
+
|
|
1670
|
+
[rowChanges addObject:rowChange];
|
|
1671
|
+
count++;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1675
|
+
index--;
|
|
1676
|
+
else
|
|
1677
|
+
index++;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
if ((numberOfInsertOperationsToManuallyAdd > 0) && (flexibleRangePinSideInsertDiff > 0))
|
|
1682
|
+
{
|
|
1683
|
+
// Manually add INSERT operations.
|
|
1684
|
+
//
|
|
1685
|
+
// These operations represent the objects that got pulled into the final range,
|
|
1686
|
+
// even though the items themselves didn't change.
|
|
1687
|
+
//
|
|
1688
|
+
// They are to go pin side.
|
|
1689
|
+
//
|
|
1690
|
+
// Note: This code path is only taken if using a flexibleRange
|
|
1691
|
+
|
|
1692
|
+
NSUInteger i = 0;
|
|
1693
|
+
NSUInteger count = 0;
|
|
1694
|
+
|
|
1695
|
+
NSUInteger index;
|
|
1696
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1697
|
+
index = finalRangeMin;
|
|
1698
|
+
else
|
|
1699
|
+
index = finalRangeLength - 1;
|
|
1700
|
+
|
|
1701
|
+
while ((count < numberOfInsertOperationsToManuallyAdd) && (i < flexibleRangePinSideInsertDiff))
|
|
1702
|
+
{
|
|
1703
|
+
// We need to be careful not to step on existing rowChanges.
|
|
1704
|
+
// If there is an existing insert for this index, we need to continue onto the next index.
|
|
1705
|
+
// If there is an existing move to this index, we need to continue onto the next index.
|
|
1706
|
+
// If there is an existing update for this index, we need to change it to an insert.
|
|
1707
|
+
//
|
|
1708
|
+
// Note: I don't think the update scenario is actually possible.
|
|
1709
|
+
|
|
1710
|
+
BOOL found = NO;
|
|
1711
|
+
|
|
1712
|
+
for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1713
|
+
{
|
|
1714
|
+
if (rowChange->type == YapDatabaseViewChangeInsert ||
|
|
1715
|
+
rowChange->type == YapDatabaseViewChangeMove)
|
|
1716
|
+
{
|
|
1717
|
+
if (rowChange->finalIndex == index && [rowChange->finalGroup isEqualToString:group])
|
|
1718
|
+
{
|
|
1719
|
+
found = YES;
|
|
1720
|
+
break;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
1724
|
+
{
|
|
1725
|
+
if (rowChange->finalIndex == index && [rowChange->finalGroup isEqualToString:group])
|
|
1726
|
+
{
|
|
1727
|
+
rowChange->type = YapDatabaseViewChangeInsert;
|
|
1728
|
+
|
|
1729
|
+
count++;
|
|
1730
|
+
found = YES;
|
|
1731
|
+
break;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
if (!found)
|
|
1737
|
+
{
|
|
1738
|
+
YapDatabaseViewRowChange *rowChange =
|
|
1739
|
+
[YapDatabaseViewRowChange insertKey:nil inGroup:group atIndex:index];
|
|
1740
|
+
|
|
1741
|
+
[rowChanges addObject:rowChange];
|
|
1742
|
+
count++;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1746
|
+
index++;
|
|
1747
|
+
else
|
|
1748
|
+
index--;
|
|
1749
|
+
|
|
1750
|
+
i++;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
numberOfInsertOperationsToManuallyAdd -= count;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
if (numberOfInsertOperationsToManuallyAdd > 0)
|
|
1757
|
+
{
|
|
1758
|
+
// Manually add INSERT operations.
|
|
1759
|
+
//
|
|
1760
|
+
// These operations represent the objects that got pulled into the final range,
|
|
1761
|
+
// even though the items themselves didn't change.
|
|
1762
|
+
//
|
|
1763
|
+
// They are to go at the end opposite the pin.
|
|
1764
|
+
|
|
1765
|
+
NSUInteger count = 0;
|
|
1766
|
+
|
|
1767
|
+
NSUInteger index;
|
|
1768
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1769
|
+
index = finalRangeLength - 1;
|
|
1770
|
+
else
|
|
1771
|
+
index = 0;
|
|
1772
|
+
|
|
1773
|
+
while (count < numberOfInsertOperationsToManuallyAdd)
|
|
1774
|
+
{
|
|
1775
|
+
// We need to be careful not to step on existing rowChanges.
|
|
1776
|
+
// If there is an existing insert for this index, we need to continue onto the next index.
|
|
1777
|
+
// If there is an existing move to this index, we need to continue onto the next index.
|
|
1778
|
+
// If there is an existing update for this index, we need to change it to an insert.
|
|
1779
|
+
//
|
|
1780
|
+
// Note: I don't think the update scenario is actually possible.
|
|
1781
|
+
|
|
1782
|
+
BOOL found = NO;
|
|
1783
|
+
|
|
1784
|
+
for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1785
|
+
{
|
|
1786
|
+
if (rowChange->type == YapDatabaseViewChangeInsert ||
|
|
1787
|
+
rowChange->type == YapDatabaseViewChangeMove)
|
|
1788
|
+
{
|
|
1789
|
+
if (rowChange->finalIndex == index && [rowChange->finalGroup isEqualToString:group])
|
|
1790
|
+
{
|
|
1791
|
+
found = YES;
|
|
1792
|
+
break;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
1796
|
+
{
|
|
1797
|
+
if (rowChange->finalIndex == index && [rowChange->finalGroup isEqualToString:group])
|
|
1798
|
+
{
|
|
1799
|
+
rowChange->type = YapDatabaseViewChangeInsert;
|
|
1800
|
+
|
|
1801
|
+
count++;
|
|
1802
|
+
found = YES;
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
if (!found)
|
|
1809
|
+
{
|
|
1810
|
+
YapDatabaseViewRowChange *rowChange =
|
|
1811
|
+
[YapDatabaseViewRowChange insertKey:nil inGroup:group atIndex:index];
|
|
1812
|
+
|
|
1813
|
+
[rowChanges addObject:rowChange];
|
|
1814
|
+
count++;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
if (pin == YapDatabaseViewBeginning)
|
|
1818
|
+
index--;
|
|
1819
|
+
else
|
|
1820
|
+
index++;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
//
|
|
1825
|
+
// STEP 4.A : Update finalMappings if needed (by updating rangeOpts.length & rangeOpts.offset)
|
|
1826
|
+
|
|
1827
|
+
if ((originalRangeLength != finalRangeLength) || (originalRangeOffset != finalRangeOffset))
|
|
1828
|
+
{
|
|
1829
|
+
[finalMappings updateRangeOptionsForGroup:group withNewLength:finalRangeLength newOffset:finalRangeOffset];
|
|
1830
|
+
rangeOptionsChanged = YES;
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
} // for (NSString *group in rangeOptions)
|
|
1834
|
+
|
|
1835
|
+
// Step 4.B : Update finalMappings if needed (by updating visibleGroups)
|
|
1836
|
+
|
|
1837
|
+
if (rangeOptionsChanged)
|
|
1838
|
+
{
|
|
1839
|
+
[finalMappings updateVisibility];
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
//
|
|
1843
|
+
// STEP 5 : Set the originalSection & finalSection
|
|
1844
|
+
// STEP 6 : Reverse indexes for reversed groups
|
|
1845
|
+
//
|
|
1846
|
+
|
|
1847
|
+
NSSet *reverse = [originalMappings reverse];
|
|
1848
|
+
|
|
1849
|
+
for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1850
|
+
{
|
|
1851
|
+
// Set the originalSection & finalSection
|
|
1852
|
+
|
|
1853
|
+
if (rowChange->type == YapDatabaseViewChangeDelete)
|
|
1854
|
+
{
|
|
1855
|
+
rowChange->originalSection = [originalMappings sectionForGroup:rowChange->originalGroup];
|
|
1856
|
+
}
|
|
1857
|
+
else if (rowChange->type == YapDatabaseViewChangeInsert)
|
|
1858
|
+
{
|
|
1859
|
+
rowChange->finalSection = [finalMappings sectionForGroup:rowChange->finalGroup];
|
|
1860
|
+
}
|
|
1861
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
1862
|
+
{
|
|
1863
|
+
rowChange->originalSection = [originalMappings sectionForGroup:rowChange->originalGroup];
|
|
1864
|
+
rowChange->finalSection = [finalMappings sectionForGroup:rowChange->finalGroup];
|
|
1865
|
+
|
|
1866
|
+
if (rowChange->originalSection != rowChange->finalSection)
|
|
1867
|
+
{
|
|
1868
|
+
// Turn the update into a move.
|
|
1869
|
+
// If we don't do so, UITableView seems to do the wrong thing.
|
|
1870
|
+
|
|
1871
|
+
rowChange->type = YapDatabaseViewChangeMove;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
else // if (rowChange->type == YapDatabaseViewChangeMove)
|
|
1875
|
+
{
|
|
1876
|
+
rowChange->originalSection = [originalMappings sectionForGroup:rowChange->originalGroup];
|
|
1877
|
+
rowChange->finalSection = [finalMappings sectionForGroup:rowChange->finalGroup];
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// Reverse indexes for reversed groups.
|
|
1881
|
+
//
|
|
1882
|
+
// For example, if the group contains 4 items, the indexes get reversed like so:
|
|
1883
|
+
// 0 -> 3
|
|
1884
|
+
// 1 -> 2
|
|
1885
|
+
// 2 -> 1
|
|
1886
|
+
// 3 -> 0
|
|
1887
|
+
//
|
|
1888
|
+
// Basically, we find the midpoint, and then move each index to the other side of the midpoint,
|
|
1889
|
+
// but we keep its distance from the midpoint the same.
|
|
1890
|
+
|
|
1891
|
+
if ([reverse containsObject:rowChange->originalGroup])
|
|
1892
|
+
{
|
|
1893
|
+
NSUInteger count = [originalMappings visibleCountForGroup:rowChange->originalGroup];
|
|
1894
|
+
double mid = (count - 1) / 2.0;
|
|
1895
|
+
|
|
1896
|
+
rowChange->originalIndex = (NSUInteger)(mid - (rowChange->originalIndex - mid));
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
if ([reverse containsObject:rowChange->finalGroup])
|
|
1900
|
+
{
|
|
1901
|
+
NSUInteger count = [finalMappings visibleCountForGroup:rowChange->finalGroup];
|
|
1902
|
+
double mid = (count - 1) / 2.0;
|
|
1903
|
+
|
|
1904
|
+
rowChange->finalIndex = (NSUInteger)(mid - (rowChange->finalIndex - mid));
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
//
|
|
1909
|
+
// STEP 7 : Handle group consolidation
|
|
1910
|
+
//
|
|
1911
|
+
|
|
1912
|
+
BOOL oldIsUsingConsolidatedGroup = [originalMappings isUsingConsolidatedGroup];
|
|
1913
|
+
BOOL newIsUsingConsolidatedGroup = [finalMappings isUsingConsolidatedGroup];
|
|
1914
|
+
|
|
1915
|
+
if (oldIsUsingConsolidatedGroup && newIsUsingConsolidatedGroup)
|
|
1916
|
+
{
|
|
1917
|
+
//
|
|
1918
|
+
// The groups were previously consolidated, and still are.
|
|
1919
|
+
//
|
|
1920
|
+
|
|
1921
|
+
NSString *consolidatedGroupName = [originalMappings consolidatedGroupName];
|
|
1922
|
+
|
|
1923
|
+
// Step 1
|
|
1924
|
+
//
|
|
1925
|
+
// - calculate original & final offset for each group
|
|
1926
|
+
|
|
1927
|
+
NSArray *allGroups = [originalMappings allGroups];
|
|
1928
|
+
|
|
1929
|
+
NSMutableDictionary *originalOffsets = [NSMutableDictionary dictionaryWithCapacity:[allGroups count]];
|
|
1930
|
+
NSMutableDictionary *finalOffsets = [NSMutableDictionary dictionaryWithCapacity:[allGroups count]];
|
|
1931
|
+
|
|
1932
|
+
NSUInteger originalOffset = 0;
|
|
1933
|
+
NSUInteger finalOffset = 0;
|
|
1934
|
+
|
|
1935
|
+
for (NSString *group in allGroups)
|
|
1936
|
+
{
|
|
1937
|
+
[originalOffsets setObject:@(originalOffset) forKey:group];
|
|
1938
|
+
[finalOffsets setObject:@(finalOffset) forKey:group];
|
|
1939
|
+
|
|
1940
|
+
originalOffset += [originalMappings visibleCountForGroup:group];
|
|
1941
|
+
finalOffset += [finalMappings visibleCountForGroup:group];
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
// Step 2
|
|
1945
|
+
//
|
|
1946
|
+
// - change section to zero, and group to consolidatedGroupName for each change
|
|
1947
|
+
// - increment original & final row index for each change
|
|
1948
|
+
|
|
1949
|
+
for (YapDatabaseViewRowChange *rowChange in rowChanges)
|
|
1950
|
+
{
|
|
1951
|
+
if (rowChange->type == YapDatabaseViewChangeDelete)
|
|
1952
|
+
{
|
|
1953
|
+
NSUInteger oOffset = [[originalOffsets objectForKey:rowChange->originalGroup] unsignedIntegerValue];
|
|
1954
|
+
|
|
1955
|
+
rowChange->originalGroup = consolidatedGroupName;
|
|
1956
|
+
rowChange->originalSection = 0;
|
|
1957
|
+
rowChange->originalIndex += oOffset;
|
|
1958
|
+
}
|
|
1959
|
+
else if (rowChange->type == YapDatabaseViewChangeInsert)
|
|
1960
|
+
{
|
|
1961
|
+
NSUInteger fOffset = [[finalOffsets objectForKey:rowChange->finalGroup] unsignedIntegerValue];
|
|
1962
|
+
|
|
1963
|
+
rowChange->finalGroup = consolidatedGroupName;
|
|
1964
|
+
rowChange->finalSection = 0;
|
|
1965
|
+
rowChange->finalIndex += fOffset;
|
|
1966
|
+
}
|
|
1967
|
+
else if (rowChange->type == YapDatabaseViewChangeMove)
|
|
1968
|
+
{
|
|
1969
|
+
NSUInteger oOffset = [[originalOffsets objectForKey:rowChange->originalGroup] unsignedIntegerValue];
|
|
1970
|
+
NSUInteger fOffset = [[finalOffsets objectForKey:rowChange->finalGroup] unsignedIntegerValue];
|
|
1971
|
+
|
|
1972
|
+
rowChange->originalGroup = consolidatedGroupName;
|
|
1973
|
+
rowChange->originalSection = 0;
|
|
1974
|
+
rowChange->originalIndex += oOffset;
|
|
1975
|
+
|
|
1976
|
+
rowChange->finalGroup = consolidatedGroupName;
|
|
1977
|
+
rowChange->finalSection = 0;
|
|
1978
|
+
rowChange->finalIndex += fOffset;
|
|
1979
|
+
}
|
|
1980
|
+
else // if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
1981
|
+
{
|
|
1982
|
+
NSUInteger oOffset = [[originalOffsets objectForKey:rowChange->originalGroup] unsignedIntegerValue];
|
|
1983
|
+
NSUInteger fOffset = [[finalOffsets objectForKey:rowChange->finalGroup] unsignedIntegerValue];
|
|
1984
|
+
|
|
1985
|
+
rowChange->originalGroup = consolidatedGroupName;
|
|
1986
|
+
rowChange->originalSection = 0;
|
|
1987
|
+
rowChange->originalIndex += oOffset;
|
|
1988
|
+
|
|
1989
|
+
rowChange->finalGroup = consolidatedGroupName;
|
|
1990
|
+
rowChange->finalSection = 0;
|
|
1991
|
+
rowChange->finalIndex += fOffset;
|
|
1992
|
+
|
|
1993
|
+
if (rowChange->originalIndex != rowChange->finalIndex)
|
|
1994
|
+
{
|
|
1995
|
+
rowChange->type = YapDatabaseViewChangeMove;
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
else if (!oldIsUsingConsolidatedGroup && newIsUsingConsolidatedGroup)
|
|
2001
|
+
{
|
|
2002
|
+
//
|
|
2003
|
+
// Switching from groups to consolidated group
|
|
2004
|
+
//
|
|
2005
|
+
|
|
2006
|
+
NSString *consolidatedGroupName = [originalMappings consolidatedGroupName];
|
|
2007
|
+
|
|
2008
|
+
// Step 1
|
|
2009
|
+
//
|
|
2010
|
+
// - calculate the offsets for each group within the consolidated group
|
|
2011
|
+
|
|
2012
|
+
NSArray *allGroups = [originalMappings allGroups];
|
|
2013
|
+
|
|
2014
|
+
NSMutableDictionary *finalOffsets = [NSMutableDictionary dictionaryWithCapacity:[allGroups count]];
|
|
2015
|
+
NSUInteger finalOffset = 0;
|
|
2016
|
+
|
|
2017
|
+
for (NSString *group in allGroups)
|
|
2018
|
+
{
|
|
2019
|
+
[finalOffsets setObject:@(finalOffset) forKey:group];
|
|
2020
|
+
|
|
2021
|
+
finalOffset += [finalMappings visibleCountForGroup:group];
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
// Step 2
|
|
2025
|
+
//
|
|
2026
|
+
// - enumerate over every single row that was visible in the originalMappings
|
|
2027
|
+
// - check to see if its already represented in the existing array of rowChanges
|
|
2028
|
+
// - if not, then inject a move operation for it
|
|
2029
|
+
|
|
2030
|
+
NSUInteger beginningChangeCount = [rowChanges count];
|
|
2031
|
+
|
|
2032
|
+
for (NSString *group in [originalMappings visibleGroups])
|
|
2033
|
+
{
|
|
2034
|
+
NSUInteger originalSection = [originalMappings sectionForGroup:group];
|
|
2035
|
+
NSUInteger finalSection = [finalMappings sectionForGroup:group];
|
|
2036
|
+
|
|
2037
|
+
NSUInteger originalGroupCount = [originalMappings visibleCountForGroup:group];
|
|
2038
|
+
|
|
2039
|
+
for (NSUInteger originalIndex = 0; originalIndex < originalGroupCount; originalIndex++)
|
|
2040
|
+
{
|
|
2041
|
+
BOOL found = NO;
|
|
2042
|
+
NSUInteger finalIndex = originalIndex;
|
|
2043
|
+
|
|
2044
|
+
for (NSUInteger i = 0; i < beginningChangeCount; i++)
|
|
2045
|
+
{
|
|
2046
|
+
YapDatabaseViewRowChange *rowChange = [rowChanges objectAtIndex:i];
|
|
2047
|
+
|
|
2048
|
+
if (rowChange->type != YapDatabaseViewChangeInsert &&
|
|
2049
|
+
rowChange->originalSection == originalSection &&
|
|
2050
|
+
rowChange->originalIndex == originalIndex)
|
|
2051
|
+
{
|
|
2052
|
+
found = YES;
|
|
2053
|
+
break;
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
if (rowChange->type == YapDatabaseViewChangeDelete ||
|
|
2057
|
+
rowChange->type == YapDatabaseViewChangeMove )
|
|
2058
|
+
{
|
|
2059
|
+
if (rowChange->originalSection == originalSection)
|
|
2060
|
+
{
|
|
2061
|
+
if (rowChange->originalIndex < finalIndex)
|
|
2062
|
+
{
|
|
2063
|
+
// A row was deleted below our row.
|
|
2064
|
+
// So its finalIndex gets decremented.
|
|
2065
|
+
finalIndex--;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
if (rowChange->type == YapDatabaseViewChangeInsert ||
|
|
2071
|
+
rowChange->type == YapDatabaseViewChangeMove )
|
|
2072
|
+
{
|
|
2073
|
+
if (rowChange->finalSection == finalSection)
|
|
2074
|
+
{
|
|
2075
|
+
if (rowChange->finalIndex <= finalIndex)
|
|
2076
|
+
{
|
|
2077
|
+
// A row was inserted below our row.
|
|
2078
|
+
// So its finalIndex gets incremented.
|
|
2079
|
+
finalIndex++;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
if (!found)
|
|
2086
|
+
{
|
|
2087
|
+
YapDatabaseViewRowChange *op = [[YapDatabaseViewRowChange alloc] init];
|
|
2088
|
+
op->type = YapDatabaseViewChangeMove;
|
|
2089
|
+
op->key = nil;
|
|
2090
|
+
op->changes = 0;
|
|
2091
|
+
|
|
2092
|
+
op->originalGroup = group;
|
|
2093
|
+
op->originalSection = originalSection;
|
|
2094
|
+
op->originalIndex = originalIndex;
|
|
2095
|
+
|
|
2096
|
+
NSUInteger finalGroupOffset = [[finalOffsets objectForKey:group] unsignedIntegerValue];
|
|
2097
|
+
|
|
2098
|
+
op->finalGroup = consolidatedGroupName;
|
|
2099
|
+
op->finalSection = 0;
|
|
2100
|
+
op->finalIndex = finalGroupOffset + finalIndex;
|
|
2101
|
+
|
|
2102
|
+
[rowChanges addObject:op];
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
// Step 3
|
|
2108
|
+
//
|
|
2109
|
+
// - update the finalGroup/finalSection/finalIndex for every rowChange
|
|
2110
|
+
// (excluding the one's we injected)
|
|
2111
|
+
|
|
2112
|
+
for (NSUInteger i = 0; i < beginningChangeCount; i++)
|
|
2113
|
+
{
|
|
2114
|
+
YapDatabaseViewRowChange *rowChange = [rowChanges objectAtIndex:i];
|
|
2115
|
+
|
|
2116
|
+
if (rowChange->type == YapDatabaseViewChangeInsert)
|
|
2117
|
+
{
|
|
2118
|
+
NSUInteger fOffset = [[finalOffsets objectForKey:rowChange->finalGroup] unsignedIntegerValue];
|
|
2119
|
+
|
|
2120
|
+
rowChange->finalGroup = consolidatedGroupName;
|
|
2121
|
+
rowChange->finalSection = 0;
|
|
2122
|
+
rowChange->finalIndex += fOffset;
|
|
2123
|
+
}
|
|
2124
|
+
else if (rowChange->type == YapDatabaseViewChangeMove)
|
|
2125
|
+
{
|
|
2126
|
+
NSUInteger fOffset = [[finalOffsets objectForKey:rowChange->finalGroup] unsignedIntegerValue];
|
|
2127
|
+
|
|
2128
|
+
rowChange->finalGroup = consolidatedGroupName;
|
|
2129
|
+
rowChange->finalSection = 0;
|
|
2130
|
+
rowChange->finalIndex += fOffset;
|
|
2131
|
+
}
|
|
2132
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
2133
|
+
{
|
|
2134
|
+
rowChange->type = YapDatabaseViewChangeMove;
|
|
2135
|
+
|
|
2136
|
+
NSUInteger fOffset = [[finalOffsets objectForKey:rowChange->finalGroup] unsignedIntegerValue];
|
|
2137
|
+
|
|
2138
|
+
rowChange->finalGroup = consolidatedGroupName;
|
|
2139
|
+
rowChange->finalSection = 0;
|
|
2140
|
+
rowChange->finalIndex += fOffset;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
else if (oldIsUsingConsolidatedGroup && !newIsUsingConsolidatedGroup)
|
|
2145
|
+
{
|
|
2146
|
+
//
|
|
2147
|
+
// Switching from consolidated group to groups
|
|
2148
|
+
//
|
|
2149
|
+
|
|
2150
|
+
NSString *consolidatedGroupName = [originalMappings consolidatedGroupName];
|
|
2151
|
+
|
|
2152
|
+
// Step 1
|
|
2153
|
+
//
|
|
2154
|
+
// - calculate the offsets for each group within the consolidated group
|
|
2155
|
+
|
|
2156
|
+
NSArray *allGroups = [originalMappings allGroups];
|
|
2157
|
+
|
|
2158
|
+
NSMutableDictionary *originalOffsets = [NSMutableDictionary dictionaryWithCapacity:[allGroups count]];
|
|
2159
|
+
|
|
2160
|
+
NSUInteger originalOffset = 0;
|
|
2161
|
+
|
|
2162
|
+
for (NSString *group in allGroups)
|
|
2163
|
+
{
|
|
2164
|
+
[originalOffsets setObject:@(originalOffset) forKey:group];
|
|
2165
|
+
|
|
2166
|
+
originalOffset += [originalMappings visibleCountForGroup:group];
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// Step 2
|
|
2170
|
+
//
|
|
2171
|
+
// - enumerate over every single row that was visible in the originalMappings
|
|
2172
|
+
// - check to see if its already represented in the existing array of rowChanges
|
|
2173
|
+
// - if not, then inject a move operation for it
|
|
2174
|
+
|
|
2175
|
+
NSUInteger beginningChangeCount = [rowChanges count];
|
|
2176
|
+
|
|
2177
|
+
for (NSString *group in [originalMappings visibleGroups])
|
|
2178
|
+
{
|
|
2179
|
+
NSUInteger originalSection = [originalMappings sectionForGroup:group];
|
|
2180
|
+
NSUInteger finalSection = [finalMappings sectionForGroup:group];
|
|
2181
|
+
|
|
2182
|
+
NSUInteger originalGroupCount = [originalMappings visibleCountForGroup:group];
|
|
2183
|
+
|
|
2184
|
+
for (NSUInteger originalIndex = 0; originalIndex < originalGroupCount; originalIndex++)
|
|
2185
|
+
{
|
|
2186
|
+
BOOL found = NO;
|
|
2187
|
+
NSUInteger finalIndex = originalIndex;
|
|
2188
|
+
|
|
2189
|
+
for (NSUInteger i = 0; i < beginningChangeCount; i++)
|
|
2190
|
+
{
|
|
2191
|
+
YapDatabaseViewRowChange *rowChange = [rowChanges objectAtIndex:i];
|
|
2192
|
+
|
|
2193
|
+
if (rowChange->type != YapDatabaseViewChangeInsert &&
|
|
2194
|
+
rowChange->originalSection == originalSection &&
|
|
2195
|
+
rowChange->originalIndex == originalIndex)
|
|
2196
|
+
{
|
|
2197
|
+
found = YES;
|
|
2198
|
+
break;
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
if (rowChange->type == YapDatabaseViewChangeDelete ||
|
|
2202
|
+
rowChange->type == YapDatabaseViewChangeMove )
|
|
2203
|
+
{
|
|
2204
|
+
if (rowChange->originalSection == originalSection)
|
|
2205
|
+
{
|
|
2206
|
+
if (rowChange->originalIndex < finalIndex)
|
|
2207
|
+
{
|
|
2208
|
+
// A row was deleted below our row.
|
|
2209
|
+
// So its finalIndex gets decremented.
|
|
2210
|
+
finalIndex--;
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
if (rowChange->type == YapDatabaseViewChangeInsert ||
|
|
2216
|
+
rowChange->type == YapDatabaseViewChangeMove )
|
|
2217
|
+
{
|
|
2218
|
+
if (rowChange->finalSection == finalSection)
|
|
2219
|
+
{
|
|
2220
|
+
if (rowChange->finalIndex <= finalIndex)
|
|
2221
|
+
{
|
|
2222
|
+
// A row was inserted below our row.
|
|
2223
|
+
// So its finalIndex gets incremented.
|
|
2224
|
+
finalIndex++;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
if (!found)
|
|
2231
|
+
{
|
|
2232
|
+
YapDatabaseViewRowChange *op = [[YapDatabaseViewRowChange alloc] init];
|
|
2233
|
+
op->type = YapDatabaseViewChangeMove;
|
|
2234
|
+
op->key = nil;
|
|
2235
|
+
op->changes = 0;
|
|
2236
|
+
|
|
2237
|
+
NSUInteger originalGroupOffset = [[originalOffsets objectForKey:group] unsignedIntegerValue];
|
|
2238
|
+
|
|
2239
|
+
op->originalGroup = consolidatedGroupName;
|
|
2240
|
+
op->originalSection = 0;
|
|
2241
|
+
op->originalIndex = originalGroupOffset + originalIndex;
|
|
2242
|
+
|
|
2243
|
+
op->finalGroup = group;
|
|
2244
|
+
op->finalSection = finalSection;
|
|
2245
|
+
op->finalIndex = finalIndex;
|
|
2246
|
+
|
|
2247
|
+
[rowChanges addObject:op];
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
// Step 3
|
|
2253
|
+
//
|
|
2254
|
+
// - update the originalGroup/originalSection/originalIndex for every rowChange
|
|
2255
|
+
// (excluding the one's we injected)
|
|
2256
|
+
|
|
2257
|
+
for (NSUInteger i = 0; i < beginningChangeCount; i++)
|
|
2258
|
+
{
|
|
2259
|
+
YapDatabaseViewRowChange *rowChange = [rowChanges objectAtIndex:i];
|
|
2260
|
+
|
|
2261
|
+
if (rowChange->type == YapDatabaseViewChangeDelete)
|
|
2262
|
+
{
|
|
2263
|
+
NSUInteger oOffset = [[originalOffsets objectForKey:rowChange->originalGroup] unsignedIntegerValue];
|
|
2264
|
+
|
|
2265
|
+
rowChange->originalGroup = consolidatedGroupName;
|
|
2266
|
+
rowChange->originalSection = 0;
|
|
2267
|
+
rowChange->originalIndex += oOffset;
|
|
2268
|
+
}
|
|
2269
|
+
else if (rowChange->type == YapDatabaseViewChangeMove)
|
|
2270
|
+
{
|
|
2271
|
+
NSUInteger oOffset = [[originalOffsets objectForKey:rowChange->originalGroup] unsignedIntegerValue];
|
|
2272
|
+
|
|
2273
|
+
rowChange->originalGroup = consolidatedGroupName;
|
|
2274
|
+
rowChange->originalSection = 0;
|
|
2275
|
+
rowChange->originalIndex += oOffset;
|
|
2276
|
+
}
|
|
2277
|
+
else if (rowChange->type == YapDatabaseViewChangeUpdate)
|
|
2278
|
+
{
|
|
2279
|
+
rowChange->type = YapDatabaseViewChangeMove;
|
|
2280
|
+
|
|
2281
|
+
NSUInteger oOffset = [[originalOffsets objectForKey:rowChange->originalGroup] unsignedIntegerValue];
|
|
2282
|
+
|
|
2283
|
+
rowChange->originalGroup = consolidatedGroupName;
|
|
2284
|
+
rowChange->originalSection = 0;
|
|
2285
|
+
rowChange->originalIndex += oOffset;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
/**
|
|
2292
|
+
* This method applies the given mappings to the processed list of section changes.
|
|
2293
|
+
* It will filter the sectionChanges array to properly represent the configuration of the mappings.
|
|
2294
|
+
**/
|
|
2295
|
+
+ (void)postProcessAndFilterSectionChanges:(NSMutableArray *)sectionChanges
|
|
2296
|
+
withOriginalMappings:(YapDatabaseViewMappings *)originalMappings
|
|
2297
|
+
finalMappings:(YapDatabaseViewMappings *)finalMappings
|
|
2298
|
+
{
|
|
2299
|
+
//
|
|
2300
|
+
// STEP 1 : Handle dynamic sections
|
|
2301
|
+
//
|
|
2302
|
+
|
|
2303
|
+
NSUInteger i = 0;
|
|
2304
|
+
while (i < [sectionChanges count])
|
|
2305
|
+
{
|
|
2306
|
+
YapDatabaseViewSectionChange *sectionChange = [sectionChanges objectAtIndex:i];
|
|
2307
|
+
|
|
2308
|
+
if (sectionChange->type == YapDatabaseViewChangeDelete)
|
|
2309
|
+
{
|
|
2310
|
+
// Although a group was deleted, the user may be allowing empty sections.
|
|
2311
|
+
// If so, we shouldn't emit a removeSection change.
|
|
2312
|
+
|
|
2313
|
+
NSUInteger originalSection = [originalMappings sectionForGroup:sectionChange->group];
|
|
2314
|
+
NSUInteger finalSection = [finalMappings sectionForGroup:sectionChange->group];
|
|
2315
|
+
|
|
2316
|
+
if ((originalSection != NSNotFound) && (finalSection == NSNotFound))
|
|
2317
|
+
{
|
|
2318
|
+
// Emit
|
|
2319
|
+
sectionChange->originalSection = originalSection;
|
|
2320
|
+
i++;
|
|
2321
|
+
}
|
|
2322
|
+
else
|
|
2323
|
+
{
|
|
2324
|
+
// Don't emit
|
|
2325
|
+
[sectionChanges removeObjectAtIndex:i];
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
else // if (sectionChange->type == YapDatabaseViewChangeInsert)
|
|
2329
|
+
{
|
|
2330
|
+
// Although a group was inserted, the user may have been allowing empty sections.
|
|
2331
|
+
// If so, we shouldn't emit an insertSection change.
|
|
2332
|
+
|
|
2333
|
+
NSUInteger originalSection = [originalMappings sectionForGroup:sectionChange->group];
|
|
2334
|
+
NSUInteger finalSection = [finalMappings sectionForGroup:sectionChange->group];
|
|
2335
|
+
|
|
2336
|
+
if ((originalSection == NSNotFound) && (finalSection != NSNotFound))
|
|
2337
|
+
{
|
|
2338
|
+
// Emit
|
|
2339
|
+
sectionChange->finalSection = finalSection;
|
|
2340
|
+
i++;
|
|
2341
|
+
}
|
|
2342
|
+
else
|
|
2343
|
+
{
|
|
2344
|
+
// Don't emit
|
|
2345
|
+
[sectionChanges removeObjectAtIndex:i];
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
//
|
|
2351
|
+
// STEP 2 : Handle group consolidation
|
|
2352
|
+
//
|
|
2353
|
+
|
|
2354
|
+
BOOL oldIsUsingConsolidatedGroup = [originalMappings isUsingConsolidatedGroup];
|
|
2355
|
+
BOOL newIsUsingConsolidatedGroup = [finalMappings isUsingConsolidatedGroup];
|
|
2356
|
+
|
|
2357
|
+
if (oldIsUsingConsolidatedGroup && newIsUsingConsolidatedGroup)
|
|
2358
|
+
{
|
|
2359
|
+
//
|
|
2360
|
+
// The groups were previously consolidated, and still are.
|
|
2361
|
+
//
|
|
2362
|
+
|
|
2363
|
+
// - clear section changes (everything stays within consolidated group)
|
|
2364
|
+
|
|
2365
|
+
[sectionChanges removeAllObjects];
|
|
2366
|
+
}
|
|
2367
|
+
else if (!oldIsUsingConsolidatedGroup && newIsUsingConsolidatedGroup)
|
|
2368
|
+
{
|
|
2369
|
+
//
|
|
2370
|
+
// Switching from groups to consolidated group
|
|
2371
|
+
//
|
|
2372
|
+
|
|
2373
|
+
// - clear section changes (so we can set them manually)
|
|
2374
|
+
|
|
2375
|
+
[sectionChanges removeAllObjects];
|
|
2376
|
+
|
|
2377
|
+
// - insert section delete for all original sections
|
|
2378
|
+
|
|
2379
|
+
NSUInteger originalSection = 0;
|
|
2380
|
+
for (NSString *originalGroup in [originalMappings visibleGroups])
|
|
2381
|
+
{
|
|
2382
|
+
YapDatabaseViewSectionChange *deleteOp = [YapDatabaseViewSectionChange deleteGroup:originalGroup];
|
|
2383
|
+
deleteOp->originalSection = originalSection;
|
|
2384
|
+
|
|
2385
|
+
[sectionChanges addObject:deleteOp];
|
|
2386
|
+
originalSection++;
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// - insert section insert for consolidated group
|
|
2390
|
+
|
|
2391
|
+
NSString *consolidatedGroupName = [originalMappings consolidatedGroupName];
|
|
2392
|
+
|
|
2393
|
+
YapDatabaseViewSectionChange *insertOp = [YapDatabaseViewSectionChange insertGroup:consolidatedGroupName];
|
|
2394
|
+
insertOp->finalSection = 0;
|
|
2395
|
+
|
|
2396
|
+
[sectionChanges addObject:insertOp];
|
|
2397
|
+
}
|
|
2398
|
+
else if (oldIsUsingConsolidatedGroup && !newIsUsingConsolidatedGroup)
|
|
2399
|
+
{
|
|
2400
|
+
//
|
|
2401
|
+
// Switching from consolidated group to groups
|
|
2402
|
+
//
|
|
2403
|
+
|
|
2404
|
+
// - clear section changes (so we can set them manually)
|
|
2405
|
+
|
|
2406
|
+
[sectionChanges removeAllObjects];
|
|
2407
|
+
|
|
2408
|
+
// - insert section delete for consolidatedGroup
|
|
2409
|
+
|
|
2410
|
+
NSString *consolidatedGroupName = [originalMappings consolidatedGroupName];
|
|
2411
|
+
|
|
2412
|
+
YapDatabaseViewSectionChange *deleteOp = [YapDatabaseViewSectionChange deleteGroup:consolidatedGroupName];
|
|
2413
|
+
deleteOp->originalSection = 0;
|
|
2414
|
+
|
|
2415
|
+
[sectionChanges addObject:deleteOp];
|
|
2416
|
+
|
|
2417
|
+
// - insert section insert for all final sections
|
|
2418
|
+
|
|
2419
|
+
NSUInteger finalSection = 0;
|
|
2420
|
+
for (NSString *finalGroup in [finalMappings visibleGroups])
|
|
2421
|
+
{
|
|
2422
|
+
YapDatabaseViewSectionChange *insertOp = [YapDatabaseViewSectionChange insertGroup:finalGroup];
|
|
2423
|
+
insertOp->finalSection = finalSection;
|
|
2424
|
+
|
|
2425
|
+
[sectionChanges addObject:insertOp];
|
|
2426
|
+
finalSection++;
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
+ (void)getSectionChanges:(NSArray **)sectionChangesPtr
|
|
2432
|
+
rowChanges:(NSArray **)rowChangesPtr
|
|
2433
|
+
withOriginalMappings:(YapDatabaseViewMappings *)originalMappings
|
|
2434
|
+
finalMappings:(YapDatabaseViewMappings *)finalMappings
|
|
2435
|
+
fromChanges:(NSArray *)changes
|
|
2436
|
+
{
|
|
2437
|
+
NSMutableArray *sectionChanges = nil;
|
|
2438
|
+
NSMutableArray *rowChanges = nil;
|
|
2439
|
+
|
|
2440
|
+
[originalMappings setAutoConsolidatingDisabled:YES]; // disable during processing
|
|
2441
|
+
[finalMappings setAutoConsolidatingDisabled:YES]; // disable during processing
|
|
2442
|
+
|
|
2443
|
+
// PRE-PROCESSING
|
|
2444
|
+
//
|
|
2445
|
+
// Remove any items from the changes array that don't concern us.
|
|
2446
|
+
|
|
2447
|
+
[self preProcessChanges:changes
|
|
2448
|
+
withOriginalMappings:originalMappings
|
|
2449
|
+
finalMappings:finalMappings
|
|
2450
|
+
andGetSectionChanges:§ionChanges
|
|
2451
|
+
rowChanges:&rowChanges];
|
|
2452
|
+
|
|
2453
|
+
//
|
|
2454
|
+
// PROCESSING
|
|
2455
|
+
//
|
|
2456
|
+
// This is where the magic happens.
|
|
2457
|
+
// Calculates original and final index of every change.
|
|
2458
|
+
|
|
2459
|
+
[self processRowChanges:rowChanges];
|
|
2460
|
+
|
|
2461
|
+
// CONSOLIDATION
|
|
2462
|
+
//
|
|
2463
|
+
// Merge multiple changes to same row into a single change.
|
|
2464
|
+
// Merge multiple changes to a group into a zero or one change.
|
|
2465
|
+
|
|
2466
|
+
[self consolidateRowChanges:rowChanges];
|
|
2467
|
+
|
|
2468
|
+
[self consolidateSectionChanges:sectionChanges];
|
|
2469
|
+
|
|
2470
|
+
//
|
|
2471
|
+
// POST-PROCESSING
|
|
2472
|
+
//
|
|
2473
|
+
// This is where we apply the mappings to filter & alter the changeset.
|
|
2474
|
+
|
|
2475
|
+
[self postProcessAndFilterRowChanges:rowChanges
|
|
2476
|
+
withOriginalMappings:originalMappings
|
|
2477
|
+
finalMappings:finalMappings];
|
|
2478
|
+
|
|
2479
|
+
[self postProcessAndFilterSectionChanges:sectionChanges
|
|
2480
|
+
withOriginalMappings:originalMappings
|
|
2481
|
+
finalMappings:finalMappings];
|
|
2482
|
+
|
|
2483
|
+
//
|
|
2484
|
+
// DONE
|
|
2485
|
+
//
|
|
2486
|
+
|
|
2487
|
+
[originalMappings setAutoConsolidatingDisabled:NO];
|
|
2488
|
+
[finalMappings setAutoConsolidatingDisabled:NO];
|
|
2489
|
+
|
|
2490
|
+
if (sectionChangesPtr) *sectionChangesPtr = sectionChanges;
|
|
2491
|
+
if (rowChangesPtr) *rowChangesPtr = rowChanges;
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
@end
|