// // FlycutStore.m // Flycut // // Flycut by Gennadiy Potapov and contributors. Based on Jumpcut by Steve Cook. // Copyright 2011 General Arcade. All rights reserved. // // This code is open-source software subject to the MIT License; see the homepage // at for details. // // #import "FlycutStore.h" #import "FlycutClipping.h" @implementation FlycutStore -(id) init { return [self initRemembering:20 displaying:10 withDisplayLength:40 ]; } -(id) initRemembering:(int)nowRemembering displaying:(int)nowDisplaying withDisplayLength:(int)displayLength { [super init]; jcList = [[NSMutableArray alloc] init]; [self setRememberNum:nowRemembering]; [self setDisplayNum:nowDisplaying]; [self setDisplayLen:displayLength]; return self; } -(int) indexOfClipping:(NSString *)clipping ofType:(NSString *)type fromAppLocalizedName:(NSString *)appLocalizedName fromAppBundleURL:(NSString *)bundleURL atTimestamp:(int) timestamp{ if ([clipping length] == 0) { return -1; } // Clipping object FlycutClipping * newClipping; // Create clipping newClipping = [[FlycutClipping alloc] initWithContents:clipping withType:type withDisplayLength:[self displayLen] withAppLocalizedName:appLocalizedName withAppBundleURL:bundleURL withTimestamp:timestamp]; int result = [self indexOfClipping: newClipping]; [newClipping release]; return result; } -(int) indexOfClipping:(FlycutClipping*) clipping{ return [self indexOfClipping:clipping afterIndex:-1]; } -(int) indexOfClipping:(FlycutClipping*) clipping afterIndex:(int) after{ NSUInteger index = [jcList indexOfObject:clipping inRange:NSMakeRange(after + 1, [jcList count] - (after + 1) )]; if ( NSNotFound == index ) { return -1; } return (int)index; } // Add a clipping -(bool) addClipping:(NSString *)clipping ofType:(NSString *)type fromAppLocalizedName:(NSString *)appLocalizedName fromAppBundleURL:(NSString *)bundleURL atTimestamp:(int) timestamp{ if ([clipping length] == 0) { return NO; } // Clipping object FlycutClipping * newClipping; // Create clipping newClipping = [[FlycutClipping alloc] initWithContents:clipping withType:type withDisplayLength:[self displayLen] withAppLocalizedName:appLocalizedName withAppBundleURL:bundleURL withTimestamp:timestamp]; [self addClipping:newClipping]; [newClipping release]; return YES; } -(bool) removeDuplicates{ return [[[NSUserDefaults standardUserDefaults] valueForKey:@"removeDuplicates"] boolValue]; } -(void) addClipping:(FlycutClipping*) clipping{ [self insertClipping:clipping atIndex:0]; } -(void) insertClipping:(FlycutClipping*) clipping atIndex:(int) index{ [self delegateBeginUpdates]; int moveFromIndex = -1; if ([jcList containsObject:clipping] && [self removeDuplicates]) { moveFromIndex = (int)[jcList indexOfObject:clipping]; [jcList removeObject:clipping]; } // Push it onto our recent clippings stack if ( index < [jcList count] ) { [jcList insertObject:clipping atIndex:index]; } else { // If the index is beyond the current count then just append it and disregard requested index. // This doesn't alter the remember number and the jcList is self-growing so it is fine to append. index = [jcList count]; [jcList addObject:clipping]; } if ( moveFromIndex >= 0 ) [self delegateMoveClippingAtIndex:moveFromIndex toIndex:index]; else [self delegateInsertClippingAtIndex:index]; // Delete clippings older than jcRememberNum while ( [jcList count] > jcRememberNum ) { [jcList removeObjectAtIndex:jcRememberNum]; [self delegateDeleteClippingAtIndex:(jcRememberNum-1)]; // -1 for before-add indexing } [self delegateEndUpdates]; } -(void) addClipping:(NSString *)clipping ofType:(NSString *)type withPBCount:(int *)pbCount { [self addClipping:clipping ofType:type fromAppLocalizedName:@"PBCount" fromAppBundleURL:nil atTimestamp:0]; } // Clear remembered and listed -(void) clearList { [self delegateBeginUpdates]; for ( int i = (int)[jcList count] ; i > 0 ; i-- ) [self delegateDeleteClippingAtIndex:(i-1)]; NSMutableArray *emptyJCList; emptyJCList = [[NSMutableArray alloc] init]; [jcList release]; jcList = emptyJCList; [self delegateEndUpdates]; } -(void) mergeList { NSString *merge = [[[[jcList reverseObjectEnumerator] allObjects] valueForKey:@"clipContents"] componentsJoinedByString:@"\n"]; [self addClipping:merge ofType:NSStringFromClass([merge class]) fromAppLocalizedName:@"Merge" fromAppBundleURL:nil atTimestamp:0]; } -(void) clearItem:(int)index { [self delegateBeginUpdates]; [jcList removeObjectAtIndex:index]; [self delegateDeleteClippingAtIndex:index]; [self delegateEndUpdates]; } -(void) clippingMoveToTop:(int)index { [self clippingMoveFrom:index To:0]; } -(void) clippingMoveFrom:(int)index To:(int)toIndex { [self delegateBeginUpdates]; FlycutClipping *clipping = [jcList objectAtIndex:index]; [jcList insertObject:clipping atIndex:toIndex]; [jcList removeObjectAtIndex:index+1]; [self delegateMoveClippingAtIndex:index toIndex:toIndex]; [self delegateEndUpdates]; } // Set various values -(void) setRememberNum:(int)nowRemembering { if ( nowRemembering > 0 ) { jcRememberNum = nowRemembering; if ( [jcList count] > jcRememberNum ) { [self delegateBeginUpdates]; while ( [jcList count] > jcRememberNum ) { [jcList removeObjectAtIndex:jcRememberNum]; [self delegateDeleteClippingAtIndex:jcRememberNum]; } [self delegateEndUpdates]; } } } -(void) setDisplayNum:(int)nowDisplaying { if ( nowDisplaying > 0 ) { jcDisplayNum = nowDisplaying; } } -(void) setDisplayLen:(int)newDisplayLength { if ( newDisplayLength > 0 ) { jcDisplayLen = newDisplayLength; for (FlycutClipping *aClipping in jcList) { [aClipping setDisplayLength:newDisplayLength]; } } } -(int) rememberNum { return jcRememberNum; } -(int) displayLen { return jcDisplayLen; } -(int) jcListCount { return [jcList count]; } -(FlycutClipping *) clippingAtPosition:(int)index { if ( index >= [jcList count] ) { return nil; } else { return [[jcList objectAtIndex:index] clipping]; } } -(NSString *) clippingContentsAtPosition:(int)index { if ( index >= [jcList count] ) { return nil; } else { return [NSString stringWithString:[[jcList objectAtIndex:index] contents]]; } } -(NSString *) clippingDisplayStringAtPosition:(int)index { return [[jcList objectAtIndex:index] displayString]; } -(NSString *) clippingTypeAtPosition:(int)index { NSString *returnString; returnString = [NSString stringWithString:[[jcList objectAtIndex:index] type]]; // return [[jcList objectAtIndex:index] type]; return returnString; } -(NSArray *) previousContents:(int)howMany { NSRange theRange; NSArray *subArray; NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease]; NSEnumerator *enumerator; FlycutClipping *aClipping; theRange.location = 0; theRange.length = howMany; if ( howMany > [jcList count] ) { subArray = jcList; } else { subArray = [jcList subarrayWithRange:theRange]; } enumerator = [subArray reverseObjectEnumerator]; while ( aClipping = [enumerator nextObject] ) { [returnArray insertObject:[aClipping contents] atIndex:0]; } return returnArray; } -(NSArray *) previousDisplayStrings:(int)howMany { return [self previousDisplayStrings:howMany containing:nil]; } -(NSArray *) previousDisplayStrings:(int)howMany containing:(NSString*)search { NSRange theRange; NSArray *subArray; NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease]; NSEnumerator *enumerator; FlycutClipping *aClipping; // If we have a search, do that. Pretty much a mix of the other two paths below, but separated out to avoid extra processing. if (nil != search && search.length > 0) { subArray = [jcList copy]; enumerator = [subArray objectEnumerator]; int index = 0; while ( aClipping = [enumerator nextObject] ) { // Forward enumerator so we find the most recent N matches if ([[self clippingContentsAtPosition:index] rangeOfString:search].location != NSNotFound) { [returnArray insertObject:[aClipping displayString] atIndex:0]; howMany--; if (0 == howMany) break; } index++; } return [[returnArray reverseObjectEnumerator] allObjects]; // Reverse the results since the caller expects the most recent to be last. } theRange.location = 0; theRange.length = howMany; if ( howMany > [jcList count] ) { subArray = jcList; } else { subArray = [jcList subarrayWithRange:theRange]; } enumerator = [subArray reverseObjectEnumerator]; while ( aClipping = [enumerator nextObject] ) { [returnArray insertObject:[aClipping displayString] atIndex:0]; } return returnArray; } -(NSArray *) previousIndexes:(int)howMany containing:(NSString*)search // This method is in newest-first order. { NSArray *subArray; NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease]; NSEnumerator *enumerator; FlycutClipping *aClipping; // If we have a search, do that. if (nil != search && search.length > 0) { subArray = [jcList copy]; enumerator = [subArray objectEnumerator]; int index = 0; while ( aClipping = [enumerator nextObject] ) { // Forward enumerator so we find the most recent N matches if ([[self clippingContentsAtPosition:index] rangeOfString:search].location != NSNotFound) { [returnArray addObject:[NSNumber numberWithInt:index]]; howMany--; if (0 == howMany) break; } index++; } } else { for ( int i = 0 ; i < howMany ; i++ ) [returnArray addObject:[NSNumber numberWithInt:i]]; } return returnArray; } -(void) delegateBeginUpdates { if ( self.delegate && [self.delegate respondsToSelector:@selector(beginUpdates)] ) [self.delegate beginUpdates]; } -(void) delegateEndUpdates { if ( self.delegate && [self.delegate respondsToSelector:@selector(endUpdates)] ) [self.delegate endUpdates]; } -(void) delegateInsertClippingAtIndex:(int)index { if ( self.delegate && [self.delegate respondsToSelector:@selector(insertClippingAtIndex:)] ) [self.delegate insertClippingAtIndex:index]; } -(void) delegateDeleteClippingAtIndex:(int)index { if ( self.delegate && [self.delegate respondsToSelector:@selector(deleteClippingAtIndex:)] ) [self.delegate deleteClippingAtIndex:index]; } -(void) delegateReloadClippingAtIndex:(int)index { if ( self.delegate && [self.delegate respondsToSelector:@selector(reloadClippingAtIndex:)] ) [self.delegate reloadClippingAtIndex:index]; } -(void) delegateMoveClippingAtIndex:(int)index toIndex:(int)newIndex { if ( self.delegate && [self.delegate respondsToSelector:@selector(moveClippingAtIndex:toIndex:)] ) [self.delegate moveClippingAtIndex:index toIndex:newIndex]; } -(void) dealloc { // Free preferences jcRememberNum = 0; jcDisplayNum = 0; jcDisplayLen = 0; // Free collections [jcList release]; [super dealloc]; } @end