2011-04-06 6 views
4

내 프로젝트 중 하나에서 상당히 복잡한 NSTextView 하위 클래스가 있습니다. 현재 인라인 찾기 바 (예 : Safari, Xcode)를 사용하여 찾기/바꾸기 작업을 수행하고 바꾸기 작업에 대해 실행 취소/다시 실행을 제대로 지원하려고합니다.NSTextView replaceCharactersInRange : withString : shouldChangeTextInRanges : replacementStrings :

모두 바꾸기 명령을 단일 명령으로 실행하려면 (텍스트보기에서 8 개의 대체 항목이있는 경우 한 번에 8 개의 대체 항목을 실행 취소해야합니다).

교환을 확인한 후 전화 할 수있는 shouldChangeTextInRanges:replaceStrings:에 해당하는 것이 있는지 궁금합니다. 나는 replaceCharactersInRanges:withStrings: 또는 이와 유사한 것이있을 것으로 예상했으나있을 것 같지 않습니다.

제가 생각할 수있는 유일한 방법은 shouldChangeTextInRanges:replaceStrings:에 대한 호출로 먼저 확인한 다음 replaceCharactersInRange:withString:으로 전화를 걸어 텍스트보기의 전체 범위와 새 문자열 (대체 내용 포함)을 두 번째로 호출하는 것입니다 논의.

이것은 불필요한 것으로 보입니다. 그렇지 않으면 전체 문자열을 바꾸고 싶지 않습니다. 어떤 아이디어?

답변

4

을 나는이 알아 낸있어 생각 몇 가지 땜질 후. 조쉬, 내가 너의 제안을 사용했다. 나는 당신이 당신의 제안을 편집했거나 그냥 삭제했는지 모르겠다. 그러나 그것이 사라져서 내 대답에서 인용 할 수는 없다.

어쨌든 replaceCharactersInRange:withString:을 호출 할 때마다 바꿀 범위를 이동해야합니다. 그렇지 않으면 범위가 일치하지 않아서 나쁜 결과가 발생합니다.

// array of NSValue objects storing an NSRange 
NSArray *replaceRanges = [self replaceRanges]; 
NSString *replaceString = [self replaceString]; 
// array of NSString objects you are going to use for the replace operation, just replaceString repeated [replaceRanges count] times 
NSArray *replaceStrings = [self replaceStrings]; 
NSTextView *textView = [self textView]; 
// the amount we have to shift subequent replace ranges after each call to replaceCharactersInRange:withString: 
NSInteger locationShift = 0; 

// check to makes sure the replace can occur 
if ([textView shouldChangeTextInRanges:replaceRanges replacementStrings:replaceStrings]) { 
    // we want to treat all these replacements as a single replacement for undo purposes 
    [[textView textStorage] beginEditing]; 

    for (NSValue *rangeValue in replaceRanges) { 
     NSRange range = [rangeValue rangeValue]; 

     // replace the range shifted by locationShift with our replaceString 
     [[textView textStorage] replaceCharactersInRange:NSMakeRange(range.location + locationShift, range.length) withString:replaceString]; 

     // update the shift amount, which is the difference between our replaced string length and the original match length 
     locationShift += [replaceString length] - range.length; 
    } 
    // end the grouping operation 
    [[textView textStorage] endEditing]; 
} 

이 잘 작동하고 지원하는 모든 대체 한 번에 취소되고이 작업 결과를 취소, 예상대로 취소 : 여기에 결국 것입니다.

어쨌든 Josh에게 감사드립니다. 그의 대답은 저에게 올바른 방향으로 지적 해주었습니다.

+0

시도하지 않고 입력했기 때문에 삭제했습니다. 컴파일/실행을 시도 할 때 유용하지 못했습니다. 그것이 도움이 되었기 때문에 다행! 나는 후손을 위해 그것을 삭제했다. –

+0

좋은 질문, BTW, 그리고 좋은 솔루션! –

0

자동으로 그룹화되지 않기 때문에 실행 취소가 놀랍습니다. 그러나 수동으로 실행 취소 그룹화를 수행 할 수 있습니다. 직접 역 동작을 설정해야합니다. 희망이 올바른 방향을 가리 킵니다 :

- (BOOL)shouldChangeTextInRanges:(NSArray *)affectedRanges replacementStrings:(NSArray *)replacementStrings { 

    NSUndoManager * undoMan = [self undoManager]; 
    [undoMan beginUndoGrouping]; 
    NSEnumerator stringEnumerator = [replacementStrings objectEnumerator]; 
    for(NSRange thisRange in affectedRanges){ 
     NSString * thisString = [stringEnumerator nextObject]; 
     NSTextStorage * textStore = [self textStorage]; 
     [[undoMan prepareWithInvocationTarget:textStore] 
       replaceCharactersInRange:thisRange 
           withString:[textStore attributedSubstringFromRange:thisRange]]; 

     [textStore replaceCharactersInRange:thisRange withString:thisString]; 
    } 
    [undoMan endUndoGrouping]; 
    [undoMan setActionName:@"Replace All"]; 

    return NO; // because we just did it by hand 
} 
+0

향후 히스토리 작성자를 위해 :이 코드는 컴파일되지 않습니다! willbur1984가 도움이되었다고 표시했기 때문에 삭제 빈에서 가져 왔습니다. –

관련 문제