Revision: 12590
          http://bibdesk.svn.sourceforge.net/bibdesk/?rev=12590&view=rev
Author:   amaxwell
Date:     2008-01-19 19:44:37 -0800 (Sat, 19 Jan 2008)

Log Message:
-----------
Add a class that uses Search Kit's asynchronous searching in a thread and sends 
callbacks to the document.  

Fixes beachball when searching a very large file from a user (25000 items) by 
displaying search results incrementally.  Most of the overhead was internal to 
Search Kit, copying document URLs.

Increased batch interval for search results from 100 to 1024, so in most cases 
the incremental result display won't even be noticed.

Tested with smart group, library group, Library of Congress search group.  
Results appear to be the same as previous search code.

Modified Paths:
--------------
    trunk/bibdesk/BibDocument.h
    trunk/bibdesk/BibDocument.m
    trunk/bibdesk/BibDocument_Search.h
    trunk/bibdesk/BibDocument_Search.m
    trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj

Added Paths:
-----------
    trunk/bibdesk/BDSKDocumentSearch.h
    trunk/bibdesk/BDSKDocumentSearch.m

Added: trunk/bibdesk/BDSKDocumentSearch.h
===================================================================
--- trunk/bibdesk/BDSKDocumentSearch.h                          (rev 0)
+++ trunk/bibdesk/BDSKDocumentSearch.h  2008-01-20 03:44:37 UTC (rev 12590)
@@ -0,0 +1,68 @@
+//
+//  BDSKDocumentSearch.h
+//  Bibdesk
+//
+//  Created by Adam Maxwell on 1/19/08.
+/*
+ This software is Copyright (c) 2008
+ Adam Maxwell. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 
+ - Neither the name of Adam Maxwell nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
[EMAIL PROTECTED] BDSKDocumentSearch : NSObject {
+    @private;
+    SKSearchRef search;                       // active search
+    NSInvocation *callback;                   // encapsulates document target 
for callback messages
+    float maxScore;                           // maximum score encountered
+    NSMutableDictionary *originalScores;      // non-normalized scores, 
identifier URLs as keys
+    volatile int32_t isSearching __attribute__ ((aligned (4)));
+
+    // main thread access only
+    SKIndexRef currentIndex;                  // nonretained
+    NSString *currentSearchString;            // avoids duplicate searches
+    NSArray *previouslySelectedPublications;  // convenience for the document
+}
+
+// following are all thread safe; document is only used as target for the 
callback
+- (id)initWithDocument:(id)doc;
+- (void)searchForString:(NSString *)searchString index:(SKIndexRef)index 
selectedPublications:(NSArray *)selPubs;
+- (NSArray *)previouslySelectedPublications;
+
+// call when closing the document window; kills the search and prevents 
further callbacks
+- (void)terminate;
+
[EMAIL PROTECTED]
+
+// This will be sent on the main thread.  Each set only contains newly 
returned items (since the last time it was sent), but scores include properly 
normalized values for all previously returned items as well.
[EMAIL PROTECTED] NSObject (BDSKDocumentSearchCallback)
+- (void)handleSearchCallbackWithIdentifiers:(NSSet *)identifierURLs 
normalizedScores:(NSDictionary *)scores;
[EMAIL PROTECTED]

Added: trunk/bibdesk/BDSKDocumentSearch.m
===================================================================
--- trunk/bibdesk/BDSKDocumentSearch.m                          (rev 0)
+++ trunk/bibdesk/BDSKDocumentSearch.m  2008-01-20 03:44:37 UTC (rev 12590)
@@ -0,0 +1,210 @@
+//
+//  BDSKDocumentSearch.m
+//  Bibdesk
+//
+//  Created by Adam Maxwell on 1/19/08.
+/*
+ This software is Copyright (c) 2008
+ Adam Maxwell. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 
+ - Neither the name of Adam Maxwell nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "BDSKDocumentSearch.h"
+#import "BibDocument.h"
+#import "BibItem.h"
+#import <libkern/OSAtomic.h>
+
+static OFMessageQueue *searchQueue = nil;
+
[EMAIL PROTECTED] BDSKDocumentSearch
+
++ (void)initialize
+{
+    if (nil == searchQueue) {
+        searchQueue = [[OFMessageQueue alloc] init];
+        [searchQueue startBackgroundProcessors:1];
+    }
+}
+
+- (id)initWithDocument:(id)doc;
+{
+    self = [super init];
+    if (self) {
+        SEL cb = 
@selector(handleSearchCallbackWithIdentifiers:normalizedScores:);
+        NSMethodSignature *sig = [doc methodSignatureForSelector:cb];
+        NSParameterAssert(nil != sig);
+        NSInvocation *invocation = [NSInvocation 
invocationWithMethodSignature:sig];
+        [invocation setTarget:doc];
+        [invocation setSelector:cb];
+        
+        callback = [invocation retain];
+        originalScores = [NSMutableDictionary new];
+        isSearching = 0;
+    }
+    return self;
+}
+
+// owner should have already sent -terminate; sending it from -dealloc causes 
resurrection
+- (void)dealloc
+{
+    [currentSearchString release];
+    [originalScores release];
+    [callback release];
+    [previouslySelectedPublications release];
+    [super dealloc];
+}
+
+- (void)_cancelSearch;
+{
+    if (NULL != search) {
+        // set first in case this is called while we're working
+        OSAtomicCompareAndSwap32Barrier(1, 0, (int32_t *)&isSearching);
+        SKSearchCancel(search);
+        CFRelease(search);
+        search = NULL;
+    }    
+}
+
+- (void)cancelSearch;
+{
+    [searchQueue queueSelector:@selector(_cancelSearch) forObject:self];
+}
+
+- (void)terminate;
+{
+    [self cancelSearch];
+    NSInvocation *cb = callback;
+    callback = nil;
+    [cb release];
+}
+
+- (BOOL)isSearching;
+{
+    OSMemoryBarrier();
+    return 1 == isSearching;
+}
+
+- (NSDictionary *)normalizedScores
+{
+    NSMutableDictionary *scores = [NSMutableDictionary dictionary];
+    NSEnumerator *keyEnum = [originalScores keyEnumerator];
+    id aKey;
+    while (aKey = [keyEnum nextObject]) {
+        float score = [[originalScores objectForKey:aKey] floatValue];
+        [scores setObject:[NSNumber numberWithFloat:(score/maxScore)] 
forKey:aKey];
+    }
+    return scores;
+}
+
+#define SEARCH_BUFFER_MAX 1024
+
+// array argument is so OFInvocation doesn't barf when it tries to retain the 
SKIndexRef
+- (void)backgroundSearchForString:(NSString *)searchString indexArray:(NSArray 
*)skIndexArray
+{
+    // note that the add/remove methods flush the index, so we don't have to 
do it again
+    SKIndexRef skIndex = (void *)[skIndexArray objectAtIndex:0];
+    NSParameterAssert(NULL == search);
+    search = SKSearchCreate(skIndex, (CFStringRef)searchString, 
kSKSearchOptionDefault);
+    
+    SKDocumentID documents[SEARCH_BUFFER_MAX];
+    float scores[SEARCH_BUFFER_MAX];
+    CFIndex i, foundCount;
+    NSMutableSet *foundURLSet = [NSMutableSet set];
+    
+    Boolean more;
+    maxScore = 0.0f;
+    
+    OSAtomicCompareAndSwap32Barrier(0, 1, (int32_t *)&isSearching);
+    NSDictionary *normalizedScores = nil;
+    [originalScores removeAllObjects];
+    
+    do {
+        
+        more = SKSearchFindMatches(search, SEARCH_BUFFER_MAX, documents, 
scores, 1.0, &foundCount);
+        
+        if (foundCount) {
+            CFURLRef documentURLs[SEARCH_BUFFER_MAX];
+            SKIndexCopyDocumentURLsForDocumentIDs(skIndex, foundCount, 
documents, documentURLs);
+            
+            for (i = 0; i < foundCount; i++) {
+                [foundURLSet addObject:(id)documentURLs[i]];
+                [originalScores setObject:[NSNumber numberWithFloat:scores[i]] 
forKey:(id)documentURLs[i]];
+                CFRelease(documentURLs[i]);
+                maxScore = MAX(maxScore, scores[i]);
+            }
+        }
+        
+        // check in case the doc is closing while a search is in progress
+        if (nil != callback) {
+            normalizedScores = [self normalizedScores];
+            [callback setArgument:&foundURLSet atIndex:2];
+            [callback setArgument:&normalizedScores atIndex:3];
+            [callback performSelectorOnMainThread:@selector(invoke) 
withObject:nil waitUntilDone:YES];
+        }
+        
+        [foundURLSet removeAllObjects];
+        
+    } while (NULL != search && foundCount && more);
+        
+    if (nil != callback) {
+        normalizedScores = [self normalizedScores];
+        [callback setArgument:&foundURLSet atIndex:2];
+        [callback setArgument:&normalizedScores atIndex:3];
+        [callback performSelectorOnMainThread:@selector(invoke) withObject:nil 
waitUntilDone:YES];
+    }
+    [self cancelSearch];  
+    OSAtomicCompareAndSwap32Barrier(1, 0, (int32_t *)&isSearching);
+}
+
+- (NSArray *)previouslySelectedPublications { return 
previouslySelectedPublications; }
+
+- (void)setPreviouslySelectedPublications:(NSArray *)selPubs
+{
+    [previouslySelectedPublications autorelease];
+    previouslySelectedPublications = [[NSArray alloc] initWithArray:selPubs 
copyItems:NO];
+}
+
+- (void)searchForString:(NSString *)searchString index:(SKIndexRef)skIndex 
selectedPublications:(NSArray *)selPubs;
+{
+    [self setPreviouslySelectedPublications:selPubs];
+    
+    // searchfield seems to send its action multiple times with the same 
search string; avoid duplicate searches
+    if (NO == [self isSearching] || (NO == [currentSearchString 
isEqualToString:searchString] && skIndex != currentIndex)) {
+        [currentSearchString autorelease];
+        currentSearchString = [searchString copy];
+        
+        if ([self isSearching])
+            [self cancelSearch];
+        
+        [searchQueue 
queueSelector:@selector(backgroundSearchForString:indexArray:) forObject:self 
withObject:searchString withObject:[NSArray arrayWithObject:(id)skIndex]];
+    }
+}
+
[EMAIL PROTECTED]

Modified: trunk/bibdesk/BibDocument.h
===================================================================
--- trunk/bibdesk/BibDocument.h 2008-01-20 00:07:24 UTC (rev 12589)
+++ trunk/bibdesk/BibDocument.h 2008-01-20 03:44:37 UTC (rev 12590)
@@ -49,7 +49,7 @@
 @class BDSKEditor, BDSKMacroWindowController, 
BDSKDocumentInfoWindowController, BDSKPreviewer, 
BDSKFileContentSearchController, BDSKCustomCiteDrawerController, 
BDSKSearchGroupViewController;
 @class BDSKAlert, BDSKStatusBar, BDSKMainTableView, BDSKGroupTableView, 
BDSKGradientView, BDSKSplitView, BDSKCollapsibleView, BDSKEdgeView, 
BDSKImagePopUpButton, BDSKColoredBox, BDSKEncodingPopUpButton, 
BDSKZoomablePDFView, FileView;
 @class BDSKWebGroupViewController, BDSKSearchButtonController;
[EMAIL PROTECTED] BDSKItemSearchIndexes, BDSKFileMigrationController;
[EMAIL PROTECTED] BDSKItemSearchIndexes, BDSKFileMigrationController, 
BDSKDocumentSearch;
 
 enum {
        BDSKOperationIgnore = NSAlertDefaultReturn, // 1
@@ -234,6 +234,7 @@
     
     BDSKItemSearchIndexes *searchIndexes;
     BDSKSearchButtonController *searchButtonController;
+    BDSKDocumentSearch *documentSearch;
     
 }
 

Modified: trunk/bibdesk/BibDocument.m
===================================================================
--- trunk/bibdesk/BibDocument.m 2008-01-20 00:07:24 UTC (rev 12589)
+++ trunk/bibdesk/BibDocument.m 2008-01-20 03:44:37 UTC (rev 12590)
@@ -123,6 +123,7 @@
 #import "NSDate_BDSKExtensions.h"
 #import "BDSKFileMigrationController.h"
 #import "NSViewAnimation_BDSKExtensions.h"
+#import "BDSKDocumentSearch.h"
 
 // these are the same as in Info.plist
 NSString *BDSKBibTeXDocumentType = @"BibTeX Database";
@@ -252,7 +253,8 @@
         
         [self registerForNotifications];
         
-        searchIndexes = [[BDSKItemSearchIndexes alloc] init];        
+        searchIndexes = [[BDSKItemSearchIndexes alloc] init];   
+        documentSearch = [[BDSKDocumentSearch alloc] 
initWithDocument:(id)self];
     }
     return self;
 }
@@ -305,6 +307,7 @@
     [searchIndexes release];
     [searchButtonController release];
     [migrationController release];
+    [documentSearch release];
     [super dealloc];
 }
 
@@ -577,7 +580,9 @@
 
     docState.isDocumentClosed = YES;
 
+    [documentSearch terminate];
     [fileSearchController terminate];
+    
     if([drawerController isDrawerOpen])
         [drawerController toggle:nil];
     [self saveSortOrder];

Modified: trunk/bibdesk/BibDocument_Search.h
===================================================================
--- trunk/bibdesk/BibDocument_Search.h  2008-01-20 00:07:24 UTC (rev 12589)
+++ trunk/bibdesk/BibDocument_Search.h  2008-01-20 03:44:37 UTC (rev 12590)
@@ -59,7 +59,7 @@
 - (IBAction)search:(id)sender;
 
 - (NSArray *)publicationsMatchingSubstring:(NSString *)searchString 
inField:(NSString *)field;
-- (NSArray *)publicationsMatchingSearchString:(NSString *)searchString 
indexName:(NSString *)field fromArray:(NSArray *)arrayToSearch;
+- (void)displayPublicationsMatchingSearchString:(NSString *)searchString 
indexName:(NSString *)field;
 
 #pragma mark Content search
 

Modified: trunk/bibdesk/BibDocument_Search.m
===================================================================
--- trunk/bibdesk/BibDocument_Search.m  2008-01-20 00:07:24 UTC (rev 12589)
+++ trunk/bibdesk/BibDocument_Search.m  2008-01-20 03:44:37 UTC (rev 12590)
@@ -62,6 +62,7 @@
 #import "BDSKSharedGroup.h"
 #import "BDSKOwnerProtocol.h"
 #import "NSViewAnimation_BDSKExtensions.h"
+#import "BDSKDocumentSearch.h"
 
 @implementation BibDocument (Search)
 
@@ -113,19 +114,19 @@
         
         if([NSString isEmptyString:searchString]){
             [shownPublications setArray:groupedPublications];
-
+            
+            [tableView deselectAll:nil];
+            [self sortPubsByKey:nil];
+            [self updateStatus];
+            if([pubsToSelect count])
+                [self selectPublications:pubsToSelect];
+            
         } else {
             
-            [shownPublications setArray:[self 
publicationsMatchingSearchString:searchString indexName:field 
fromArray:groupedPublications]];
-            if([shownPublications count] == 1)
-                pubsToSelect = [NSMutableArray 
arrayWithObject:[shownPublications lastObject]];
+            [self displayPublicationsMatchingSearchString:searchString 
indexName:field];
+
         }
-        
-        [tableView deselectAll:nil];
-        [self sortPubsByKey:nil];
-        [self updateStatus];
-        if([pubsToSelect count])
-            [self selectPublications:pubsToSelect];
+         
     }
 }
 
@@ -217,73 +218,56 @@
     return searchFieldString;
 }
 
-#define SEARCH_BUFFER_MAX 100
-        
-- (NSArray *)publicationsMatchingSearchString:(NSString *)searchString 
indexName:(NSString *)field fromArray:(NSArray *)arrayToSearch{
+- (void)handleSearchCallbackWithIdentifiers:(NSSet *)identifierURLs 
normalizedScores:(NSDictionary *)scores;
+{
+    id<BDSKOwner> owner = [self hasExternalGroupsSelected] ? [[self 
selectedGroups] firstObject] : self;    
+    BDSKPublicationsArray *pubArray = [owner publications];    
     
-    searchString = BDSKSearchKitExpressionWithString(searchString);
-    
-    NSMutableArray *toReturn = [NSMutableArray 
arrayWithCapacity:[arrayToSearch count]];
-    
-    // we need the correct BDSKPublicationsArray for access to the 
identifierURLs
-    id<BDSKOwner> owner = [self hasExternalGroupsSelected] ? [[self 
selectedGroups] firstObject] : self;
-    SKIndexRef skIndex = [[owner searchIndexes] indexForField:field];
-    BDSKPublicationsArray *pubArray = [owner publications];
-    
-    NSAssert1(NULL != skIndex, @"No index for field %@", field);
-    
-    // note that the add/remove methods flush the index, so we don't have to 
do it again
-    SKSearchRef search = SKSearchCreate(skIndex, (CFStringRef)searchString, 
kSKSearchOptionDefault);
-    
-    SKDocumentID documents[SEARCH_BUFFER_MAX];
-    float scores[SEARCH_BUFFER_MAX];
-    CFIndex i, foundCount;
-    NSMutableSet *foundURLSet = [NSMutableSet set];
-    
-    Boolean more;
-    BibItem *aPub;
-    float maxScore = 0.0f;
-    
-    do {
-        
-        more = SKSearchFindMatches(search, SEARCH_BUFFER_MAX, documents, 
scores, 1.0, &foundCount);
-        
-        if (foundCount) {
-            CFURLRef documentURLs[SEARCH_BUFFER_MAX];
-            SKIndexCopyDocumentURLsForDocumentIDs(skIndex, foundCount, 
documents, documentURLs);
-            
-            for (i = 0; i < foundCount; i++) {
-                [foundURLSet addObject:(id)documentURLs[i]];
-                aPub = [pubArray itemForIdentifierURL:(NSURL 
*)documentURLs[i]];
-                CFRelease(documentURLs[i]);
-                [aPub setSearchScore:scores[i]];
-                maxScore = MAX(maxScore, scores[i]);
-            }
-        }
-                    
-    } while (foundCount && more);
-            
-    SKSearchCancel(search);
-    CFRelease(search);
-    
     // we searched all publications, but we only want to keep the subset 
that's shown (if a group is selected)
-    NSMutableSet *identifierURLsToKeep = [NSMutableSet 
setWithArray:[arrayToSearch valueForKey:@"identifierURL"]];
+    NSMutableSet *foundURLSet = [[identifierURLs mutableCopy] autorelease];
+    NSMutableSet *identifierURLsToKeep = [NSMutableSet 
setWithArray:[groupedPublications valueForKey:@"identifierURL"]];
     [foundURLSet intersectSet:identifierURLsToKeep];
     
     NSEnumerator *keyEnum = [foundURLSet objectEnumerator];
     NSURL *aURL;
+    BibItem *aPub;
 
     // iterate and normalize search scores
     while (aURL = [keyEnum nextObject]) {
         aPub = [pubArray itemForIdentifierURL:aURL];
         if (aPub) {
-            [toReturn addObject:aPub];
-            float score = [aPub searchScore];
-            [aPub setSearchScore:(score/maxScore)];
+            [shownPublications addObject:aPub];
         }
     }
+            
+    NSEnumerator *pubEnum = [shownPublications objectEnumerator];
+    while (aPub = [pubEnum nextObject]) {
+        [aPub setSearchScore:[[scores objectForKey:[aPub identifierURL]] 
floatValue]];
+    }
+    
+    [self sortPubsByKey:nil];
+    [self updateStatus];
+    
+    [self selectPublications:[documentSearch previouslySelectedPublications]];
+}
+        
+- (void)displayPublicationsMatchingSearchString:(NSString *)searchString 
indexName:(NSString *)field {
+    searchString = BDSKSearchKitExpressionWithString(searchString);
+        
+    // we need the correct BDSKPublicationsArray for access to the 
identifierURLs
+    id<BDSKOwner> owner = [self hasExternalGroupsSelected] ? [[self 
selectedGroups] firstObject] : self;
+    SKIndexRef skIndex = [[owner searchIndexes] indexForField:field];
+    
+    NSArray *selPubs = [[self selectedPublications] retain];
+    
+    [shownPublications removeAllObjects];
+    [tableView deselectAll:nil];
+    [self sortPubsByKey:nil];
+    [self updateStatus];
+    
+    [documentSearch searchForString:searchString index:skIndex 
selectedPublications:selPubs];
+    [selPubs release];
 
-    return toReturn;
 }
 
 #pragma mark File Content Search

Modified: trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj
===================================================================
--- trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj     2008-01-20 00:07:24 UTC 
(rev 12589)
+++ trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj     2008-01-20 03:44:37 UTC 
(rev 12590)
@@ -486,6 +486,8 @@
                F97C9DBF0C4486700002EE01 /* BDSKISIWebServices.m in Sources */ 
= {isa = PBXBuildFile; fileRef = F97C9DBD0C44866F0002EE01 /* 
BDSKISIWebServices.m */; };
                F97FA7930AF56FA100C32BBA /* BDSKImageFadeAnimation.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = F97FA7910AF56FA100C32BBA /* 
BDSKImageFadeAnimation.m */; };
                F98DB3180A23C7730040D347 /* BDSKTemplate.m in Sources */ = {isa 
= PBXBuildFile; fileRef = F98DB3160A23C7730040D347 /* BDSKTemplate.m */; };
+               F990C58B0D42D58D00B5425E /* BDSKDocumentSearch.h in Headers */ 
= {isa = PBXBuildFile; fileRef = F990C5890D42D58D00B5425E /* 
BDSKDocumentSearch.h */; };
+               F990C58C0D42D58D00B5425E /* BDSKDocumentSearch.m in Sources */ 
= {isa = PBXBuildFile; fileRef = F990C58A0D42D58D00B5425E /* 
BDSKDocumentSearch.m */; };
                F9936CC60BC746C300A32DC4 /* BDSKItemSearchIndexes.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = F9936CC40BC746C300A32DC4 /* 
BDSKItemSearchIndexes.m */; };
                F9937E230AD8268E001D1DFB /* BDSKZoomablePDFView.m in Sources */ 
= {isa = PBXBuildFile; fileRef = F98F33C90892D4B700C1427D /* 
BDSKZoomablePDFView.m */; };
                F9937E250AD82690001D1DFB /* PDFDocument_BDSKExtensions.m in 
Sources */ = {isa = PBXBuildFile; fileRef = F947A01B09AA80E4004C27FF /* 
PDFDocument_BDSKExtensions.m */; };
@@ -1567,6 +1569,8 @@
                F98DB3160A23C7730040D347 /* BDSKTemplate.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= BDSKTemplate.m; sourceTree = "<group>"; };
                F98F33C80892D4B700C1427D /* BDSKZoomablePDFView.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BDSKZoomablePDFView.h; sourceTree = "<group>"; };
                F98F33C90892D4B700C1427D /* BDSKZoomablePDFView.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= BDSKZoomablePDFView.m; sourceTree = "<group>"; };
+               F990C5890D42D58D00B5425E /* BDSKDocumentSearch.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BDSKDocumentSearch.h; sourceTree = "<group>"; };
+               F990C58A0D42D58D00B5425E /* BDSKDocumentSearch.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= BDSKDocumentSearch.m; sourceTree = "<group>"; };
                F9936CC30BC746C300A32DC4 /* BDSKItemSearchIndexes.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
BDSKItemSearchIndexes.h; sourceTree = "<group>"; };
                F9936CC40BC746C300A32DC4 /* BDSKItemSearchIndexes.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= BDSKItemSearchIndexes.m; sourceTree = "<group>"; };
                F994B8F607F5F65F00751DA1 /* RelNotes.rtf */ = {isa = 
PBXFileReference; lastKnownFileType = text.rtf; path = RelNotes.rtf; sourceTree 
= "<group>"; };
@@ -2305,6 +2309,8 @@
                CE38FABE091D2D0E00BCB69D /* Document */ = {
                        isa = PBXGroup;
                        children = (
+                               F990C5890D42D58D00B5425E /* 
BDSKDocumentSearch.h */,
+                               F990C58A0D42D58D00B5425E /* 
BDSKDocumentSearch.m */,
                                F9022C66075802E300C3F701 /* BibDocument.m */,
                                CE5C29CC0AE14FEC00C3E6B5 /* 
BibDocument_Actions.m */,
                                F9022C64075802E300C3F701 /* 
BibDocument_DataSource.m */,
@@ -2904,6 +2910,7 @@
                        files = (
                                CE424A450D0F123500F824E7 /* 
BDSKCompletionServerProtocol.h in Headers */,
                                CE2E78CC0D40F6BB00340B39 /* 
BDSKMultiValueDictionary.h in Headers */,
+                               F990C58B0D42D58D00B5425E /* 
BDSKDocumentSearch.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
@@ -3880,6 +3887,7 @@
                                CE4376F70D24341E00C993CF /* 
NSViewAnimation_BDSKExtensions.m in Sources */,
                                CE83E3A60D294EE300BB7AD8 /* BDSKSortCommand.m 
in Sources */,
                                CE2E78CD0D40F6BB00340B39 /* 
BDSKMultiValueDictionary.m in Sources */,
+                               F990C58C0D42D58D00B5425E /* 
BDSKDocumentSearch.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit

Reply via email to