diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 3053b67e7..f49631587 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -242,13 +242,15 @@ Sets the content of the collection view to the content in \c anArray. This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method. It's the responsibility of your custom collection view item to interpret the object. - @param anArray the content array + + If the new content array is smaller than the previous one, note that [receiver selectionIndexes] may + refer to out of range indices. \c selectionIndexes is not changed as a result of calling the + \c setContent: method. + + @param anArray a content array */ - (void)setContent:(CPArray)anArray { - // reset the _selectionIndexes - [self setSelectionIndexes:[CPIndexSet indexSet]]; - _content = anArray; [self reloadContent]; @@ -284,9 +286,11 @@ if (!_isSelectable) { - var index = CPNotFound; + var index = CPNotFound, + itemCount = [_items count]; - while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) + // Be wary of invalid selection ranges since setContent: does not clear selection indexes. + while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < itemCount) [_items[index] setSelected:NO]; } } @@ -345,9 +349,11 @@ if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet]) return; - var index = CPNotFound; + var index = CPNotFound, + itemCount = [_items count]; - while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound) + // Be wary of invalid selection ranges since setContent: does not clear selection indexes. + while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound && index < itemCount) [_items[index] setSelected:NO]; _selectionIndexes = anIndexSet; @@ -403,7 +409,8 @@ } index = CPNotFound; - while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) + // Be wary of invalid selection ranges since setContent: does not clear selection indexes. + while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < count) [_items[index] setSelected:YES]; [self tile]; diff --git a/Tests/AppKit/CPCollectionViewTest.j b/Tests/AppKit/CPCollectionViewTest.j index eefe2a9bc..deabdecbe 100644 --- a/Tests/AppKit/CPCollectionViewTest.j +++ b/Tests/AppKit/CPCollectionViewTest.j @@ -70,11 +70,14 @@ [self assert:"selection changed: 1" equals:_globalResults]; _globalResults = nil; - // setting the same content again should still trigger the delegate but with no selection + // setContent: by itself should not affect the selection. [_collectionView setContent:content1]; - [self assert:"selection changed: 0" equals:_globalResults]; + [self assert:nil equals:_globalResults]; + // Manually clear the selection. + [_collectionView setSelectionIndexes:[CPIndexSet indexSet]]; _globalResults = nil; + // now lets change the contents [_collectionView setContent:content2]; // we set the selection to 0 again, but on the NEW content @@ -94,6 +97,19 @@ [self assert:[CPIndexSet indexSet] equals:[_collectionView selectionIndexes]]; } +- (void)testSetContentAndSelectionIndexes +{ + // Changing the content does not automatically clear the selection indexes. The previous + // selection indexes are preserved, even if now invalid or out of range. This is what + // Cocoa does and necessary to prevent a new empty selection from overwriting + // CPArrayController's selectsInsertedObjects selections. + + [_collectionView setContent:[1, 2, 3]]; + [_collectionView setSelectionIndexes:[CPIndexSet indexSetWithIndex:1]]; + [_collectionView setContent:[3, 1, 2]]; + [self assert:[CPIndexSet indexSetWithIndex:1] equals:[_collectionView selectionIndexes]]; +} + @end @implementation _CPCollectionViewWithHooks : CPCollectionView diff --git a/Tools/Documentation/postprocess/001.cleanup_headers.sh b/Tools/Documentation/postprocess/001.cleanup_headers.sh index bd271367b..4d795216f 100755 --- a/Tools/Documentation/postprocess/001.cleanup_headers.sh +++ b/Tools/Documentation/postprocess/001.cleanup_headers.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # NOTE: The working directory should be the main capp directory when this script is run # diff --git a/Tools/Documentation/postprocess/002.transform_text.sh b/Tools/Documentation/postprocess/002.transform_text.sh index 3cd354752..656af6a73 100755 --- a/Tools/Documentation/postprocess/002.transform_text.sh +++ b/Tools/Documentation/postprocess/002.transform_text.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # NOTE: The working directory should be the main capp directory when this script is run # diff --git a/Tools/Documentation/postprocess/003.markdown_readme.sh b/Tools/Documentation/postprocess/003.markdown_readme.sh index b91d7ecee..1aaf51163 100755 --- a/Tools/Documentation/postprocess/003.markdown_readme.sh +++ b/Tools/Documentation/postprocess/003.markdown_readme.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Remove the generated README.html once the build has finished. # @@ -7,4 +7,4 @@ # $1 Cappuccino documentation directory # -rm "$1"/README.html \ No newline at end of file +rm "$1"/README.html diff --git a/Tools/Documentation/preprocess/001.markdown_readme.sh b/Tools/Documentation/preprocess/001.markdown_readme.sh index 8f23e4ef4..62d153707 100755 --- a/Tools/Documentation/preprocess/001.markdown_readme.sh +++ b/Tools/Documentation/preprocess/001.markdown_readme.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # NOTE: The working directory should be the main capp directory when this script is run # diff --git a/Tools/Documentation/preprocess/002.make_headers.sh b/Tools/Documentation/preprocess/002.make_headers.sh index 72c1dfba0..e598f31ef 100755 --- a/Tools/Documentation/preprocess/002.make_headers.sh +++ b/Tools/Documentation/preprocess/002.make_headers.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # NOTE: The working directory should be the main capp directory when this script is run # diff --git a/Tools/Documentation/support/processor_setup.sh b/Tools/Documentation/support/processor_setup.sh index 83cd03737..a2ac165f5 100755 --- a/Tools/Documentation/support/processor_setup.sh +++ b/Tools/Documentation/support/processor_setup.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash function processor_msg () { diff --git a/Tools/Scripts/ci.sh b/Tools/Scripts/ci.sh index bb89cc298..4cce6225e 100755 --- a/Tools/Scripts/ci.sh +++ b/Tools/Scripts/ci.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash project_home="$(dirname "$PWD")" extras="$project_home/ci-extra.sh" diff --git a/Tools/capp_lint/capp_lint b/Tools/capp_lint/capp_lint index 4801b81db..85fc96fb2 100755 --- a/Tools/capp_lint/capp_lint +++ b/Tools/capp_lint/capp_lint @@ -280,7 +280,7 @@ class LintChecker(object): if option: default = check.get('optionDefault', False) - if not self.view.settings().get(option, default): + if self.view and not self.view.settings().get(option, default): continue line = self.line @@ -982,7 +982,7 @@ if __name__ == '__main__': print usage.replace('%prog', os.path.basename(sys.argv[0])) sys.exit(0) - checker = LintChecker(basedir=basedir, var_declarations=LintChecker.VAR_DECLARATIONS.index(options.var_declarations), verbose=options.verbose) + checker = LintChecker(basedir=basedir, view=None, var_declarations=LintChecker.VAR_DECLARATIONS.index(options.var_declarations), verbose=options.verbose) pathsToCheck = [] for filename in filenames: diff --git a/Tools/capp_lint/install.sh b/Tools/capp_lint/install.sh index f28e40904..40a90bb50 100755 --- a/Tools/capp_lint/install.sh +++ b/Tools/capp_lint/install.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash chmod +x capp_lint diff --git a/Tools/capp_lint/pre-commit b/Tools/capp_lint/pre-commit index 4729c265b..d896cd5ff 100644 --- a/Tools/capp_lint/pre-commit +++ b/Tools/capp_lint/pre-commit @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # An example hook script to verify what is about to be committed. # Called by "git commit" with no arguments. The hook should