Revision: 29194
http://sourceforge.net/p/bibdesk/svn/29194
Author: hofman
Date: 2025-04-25 16:30:07 +0000 (Fri, 25 Apr 2025)
Log Message:
-----------
Add search group server for SRU. This is a rerplacement protocol for z39.50 for
libraries. Not yet tested and not yet possible to choose in UI.
Modified Paths:
--------------
trunk/bibdesk/BDSKSearchGroup.h
trunk/bibdesk/BDSKSearchGroup.m
trunk/bibdesk/BDSKSearchGroupSheetController.h
trunk/bibdesk/BDSKSearchGroupSheetController.m
trunk/bibdesk/BDSKServerInfo.h
trunk/bibdesk/BDSKServerInfo.m
trunk/bibdesk/Base.lproj/BDSKSearchGroupSheet.xib
trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj
Added Paths:
-----------
trunk/bibdesk/BDSKSRUGroupServer.h
trunk/bibdesk/BDSKSRUGroupServer.m
Added: trunk/bibdesk/BDSKSRUGroupServer.h
===================================================================
--- trunk/bibdesk/BDSKSRUGroupServer.h (rev 0)
+++ trunk/bibdesk/BDSKSRUGroupServer.h 2025-04-25 16:30:07 UTC (rev 29194)
@@ -0,0 +1,64 @@
+//
+// BDSKSRUGroupServer.h
+// BibDesk
+//
+// Created by Christiaan Hofmanon 25/04/2025.
+/*
+ This software is Copyright (c) 2025
+ Christiaan Hofman. 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 Christiaan Hofman 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>
+#import "BDSKSearchGroup.h"
+#import "BDSKDownloader.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class BDSKServerInfo;
+
+@interface BDSKSRUGroupServer : NSObject <BDSKSearchGroupServer,
BDSKDownloadDelegate> {
+ __weak id<BDSKSearchGroup> group;
+ BDSKServerInfo *serverInfo;
+ NSString *searchTerm;
+ BDSKDownload *download;
+ BOOL failedDownload;
+ BOOL needsReset;
+ NSInteger availableResults;
+ NSInteger fetchedResults;
+ NSInteger requestedResults;
+ NSInteger limitResults;
+ NSInteger downloadState;
+ NSString *errorMessage;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
Added: trunk/bibdesk/BDSKSRUGroupServer.m
===================================================================
--- trunk/bibdesk/BDSKSRUGroupServer.m (rev 0)
+++ trunk/bibdesk/BDSKSRUGroupServer.m 2025-04-25 16:30:07 UTC (rev 29194)
@@ -0,0 +1,330 @@
+//
+// BDSKSRUGroupServer.m
+// BibDesk
+//
+// Created by Christiaan Hofmanon 25/04/2025.
+/*
+ This software is Copyright (c) 2025
+ Christiaan Hofman. 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 Christiaan Hofman 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 "BDSKSRUGroupServer.h"
+#import "BDSKServerInfo.h"
+#import "BDSKStringParser.h"
+#import "BDSKMARCParser.h"
+#import "NSString_BDSKExtensions.h"
+#import "NSURL_BDSKExtensions.h"
+
+#define MAX_RESULTS 100
+#define MAX_TOTAL_RESULTS 1000
+
+enum { BDSKIdleState, BDSKSearchState, BDSKFetchState };
+
+@interface BDSKSRUGroupServer ()
+
+@property (nonatomic, copy) NSString *searchTerm;
+
+@property (nonatomic, copy) NSString *errorMessage;
+
+- (void)resetSearch;
+- (void)fetch;
+
+- (void)startDownloadFromURL:(NSURL *)theURL;
+
+@end
+
+#pragma mark -
+
+@implementation BDSKSRUGroupServer
+
+@synthesize searchTerm, errorMessage;
+
+- (instancetype)initWithGroup:(id<BDSKSearchGroup>)aGroup
serverInfo:(BDSKServerInfo *)info {
+ self = [super init];
+ if (self) {
+ group = aGroup;
+ serverInfo = [info copy];
+ searchTerm = nil;
+ failedDownload = NO;
+ needsReset = NO;
+ availableResults = 0;
+ fetchedResults = 0;
+ limitResults = 0;
+ requestedResults = 0;
+ download = nil;
+ downloadState = BDSKIdleState;
+ errorMessage = nil;
+ }
+ return self;
+}
+
+#pragma mark BDSKSearchGroupServer protocol
+
+- (NSString *)type { return BDSKSearchGroupSRU; }
+
+- (void)reset {
+ if ([self isRetrieving])
+ [self terminate];
+ availableResults = 0;
+ fetchedResults = 0;
+}
+
+- (void)terminate {
+ [download cancel];
+ download = nil;
+ downloadState = BDSKIdleState;
+}
+
+- (void)retrieveWithSearchTerm:(NSString *)aSearchTerm {
+ if ([[[self baseComponents] URL] canConnect]) {
+ if ([[self searchTerm] isEqualToString:aSearchTerm] == NO ||
needsReset) {
+ [self setSearchTerm:aSearchTerm];
+ [self resetSearch];
+ } else if ([self isRetrieving] == NO) {
+ limitResults = MIN(availableResults, fetchedResults +
MAX_TOTAL_RESULTS);
+ [self fetch];
+ }
+ } else {
+ failedDownload = YES;
+ [self setErrorMessage:NSLocalizedString(@"Unable to connect to
server", @"error when pubmed connection fails")];
+ }
+}
+
+- (BDSKServerInfo *)serverInfo { return serverInfo; }
+
+- (void)setServerInfo:(BDSKServerInfo *)info {
+ if(serverInfo != info){
+ serverInfo = [info copy];
+ needsReset = YES;
+ }
+}
+
+- (NSInteger)numberOfFetchedResults { return fetchedResults; }
+
+- (NSInteger)numberOfAvailableResults { return availableResults; }
+
+- (BOOL)failedDownload { return failedDownload; }
+
+- (BOOL)isRetrieving { return BDSKIdleState != downloadState; }
+
+- (NSFormatter *)searchStringFormatter { return nil; }
+
+#pragma mark URLs
+
+static inline NSString *escapeHost(NSString *string) {
+ return [string
stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet
URLHostAllowedCharacterSet]];
+}
+
+static NSString *escapeDatabase(NSString *string) {
+ static NSCharacterSet *URLDatabaseOrNameAllowedCharacterSet = nil;
+ if (URLDatabaseOrNameAllowedCharacterSet == nil) {
+ NSMutableCharacterSet *tmpSet = [[NSCharacterSet
URLPathAllowedCharacterSet] mutableCopy];
+ [tmpSet removeCharactersInString:@"/"];
+ URLDatabaseOrNameAllowedCharacterSet = [tmpSet copy];
+ }
+ return [string
stringByAddingPercentEncodingWithAllowedCharacters:URLDatabaseOrNameAllowedCharacterSet];
+}
+
+- (NSURLComponents *)baseComponents {
+ NSString *host = [[self serverInfo] host];
+ NSInteger port = [[[self serverInfo] port] integerValue];
+ NSString *database = [[self serverInfo] database];
+ NSURLComponents *components = [[NSURLComponents alloc] init];
+ [components setScheme:@"http"];
+ [components setPercentEncodedHost:escapeHost(host)];
+ if (port > 0)
+ [components setPort:[NSNumber numberWithInteger:port]];
+ [components setPercentEncodedPath:[@"/"
stringByAppendingString:escapeDatabase(database)]];
+ return components;
+}
+
+- (NSURL *)searchURL {
+ NSURLComponents *components = [self baseComponents];
+ NSMutableArray *query = [NSMutableArray array];
+ NSString *version = [[[self serverInfo] options] objectForKey:@"version"]
?: @"1.1";
+ [query addObject:[@"version=" stringByAppendingString:version]];
+ [query addObject:@"operation=searchRetrieve"];
+ [query addObject:[@"query=" stringByAppendingString:[[self searchTerm]
stringByAddingPercentEscapesForQueryTerm]]];
+ [components setPercentEncodedQuery:[query componentsJoinedByString:@"&"]];
+ return [components URL];
+}
+
+- (NSURL *)fetchURL {
+ NSURLComponents *components = [self baseComponents];
+ NSMutableArray *query = [NSMutableArray array];
+ NSString *version = [[[self serverInfo] options] objectForKey:@"version"]
?: @"1.1";
+ [query addObject:[@"version=" stringByAppendingString:version]];
+ [query addObject:@"operation=searchRetrieve"];
+ [query addObject:[@"query=%@" stringByAppendingString:[[self searchTerm]
stringByAddingPercentEscapesForQueryTerm]]];
+ [query addObject:[NSString stringWithFormat:@"startRecord=%ld", 1 + [self
numberOfFetchedResults]]];
+ [query addObject:[NSString stringWithFormat:@"maximumRecords=%ld",
MIN([self numberOfAvailableResults] - [self numberOfFetchedResults],
MAX_RESULTS)]];
+ [components setPercentEncodedQuery:[query componentsJoinedByString:@"&"]];
+ return [components URL];
+}
+
+#pragma mark Search methods
+
+- (void)resetSearch {
+ [self reset];
+
+ if (NO == [NSString isEmptyString:[self searchTerm]]) {
+ // get the initial XML document with our search parameters in it
+ NSURL *initialURL = [self searchURL];
+ BDSKPRECONDITION(initialURL);
+
+ downloadState = BDSKSearchState;
+ [self startDownloadFromURL:initialURL];
+ needsReset = NO;
+ }
+}
+
+- (void)fetch {
+ if ([self numberOfAvailableResults] <= [self numberOfFetchedResults]) {
+ downloadState = BDSKIdleState;
+ [group addPublications:@[]];
+ return;
+ }
+
+ NSRange returnRange = NSMakeRange([self numberOfFetchedResults], MIN([self
numberOfAvailableResults] - [self numberOfFetchedResults], MAX_RESULTS));
+
+ NSURL *theURL = [self fetchURL];
+ BDSKPOSTCONDITION(theURL);
+
+ requestedResults = returnRange.length;
+
+ downloadState = BDSKFetchState;
+ [self startDownloadFromURL:theURL];
+}
+
+#pragma mark Downloading
+
+- (void)download:(BDSKDownload *)aDownload didCompleteWithError:(NSError
*)error {
+ if (error) {
+ // calling -cancel may call this delegate method
+ if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code]
== NSURLErrorCancelled)
+ return;
+
+ downloadState = BDSKIdleState;
+ failedDownload = YES;
+ [self setErrorMessage:[error localizedDescription]];
+
+ download = nil;
+
+ // redraw
+ [group addPublications:nil];
+ return;
+ }
+
+ failedDownload = NO;
+ NSError *presentableError;
+ NSData *data = [download data];
+
+ download = nil;
+
+ switch (downloadState) {
+ case BDSKSearchState:
+ {
+ // okay to reset state before calling -fetch
+ downloadState = BDSKIdleState;
+
+ // parse the result opf the search
+ NSXMLDocument *document = nil;
+ if (data)
+ document = [[NSXMLDocument alloc] initWithData:data
options:NSXMLNodeOptionsNone error:NULL];
+
+ if (nil != document) {
+ NSXMLElement *root = [document rootElement];
+
+ // we need to extract WebEnv, Count, and QueryKey to construct
our final URL
+ NSString *countString = [[[root
nodesForXPath:@"/zs:searchRetrieveResponse[1]/zs:numberOfRecords[1]"
error:NULL] lastObject] stringValue];
+
+ availableResults = [countString integerValue];
+ limitResults = MIN(availableResults, fetchedResults +
MAX_TOTAL_RESULTS);
+
+ [self fetch];
+
+ } else {
+
+ // no document, or zero length data from the server
+ failedDownload = YES;
+ [self setErrorMessage:NSLocalizedString(@"Unable to connect to
server", @"")];
+
+ }
+
+ break;
+ }
+ case BDSKFetchState:
+ {
+
+ NSString *string = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
+ NSArray *pubs = [BDSKMARCParser itemsFromString:string
error:&presentableError];
+
+ // the number of returned results is not always equal to what we
requested
+ // fetchedResults should track the requests to get the correct
offset
+ fetchedResults += requestedResults;
+
+ if (nil == pubs) {
+ failedDownload = YES;
+ [self setErrorMessage:[presentableError localizedDescription]];
+ // set before addPublications:
+ downloadState = BDSKIdleState;
+ [group addPublications:nil];
+ }
+ else if (limitResults > [self numberOfFetchedResults]) {
+ [group addPublications:pubs];
+ [self fetch];
+ }
+ else {
+ // set before addPublications:
+ downloadState = BDSKIdleState;
+ [group addPublications:pubs];
+ }
+ break;
+ }
+ case BDSKIdleState:
+ break;
+ default:
+ [NSException raise:NSInternalInconsistencyException
format:@"Unhandled case %ld", (long)downloadState];
+ break;
+ }
+}
+
+- (NSWindow *)downloadWindowForAuthenticationSheet:(BDSKDownload *)download {
+ return [group windowForSheetForObject:self];
+}
+
+- (void)startDownloadFromURL:(NSURL *)theURL {
+ NSURLRequest *request = [NSURLRequest requestWithURL:theURL];
+ [download cancel];
+ download = [[BDSKDownloader sharedDownloader]
startDataDownloadWithRequest:request delegate:self];
+}
+
+@end
Modified: trunk/bibdesk/BDSKSearchGroup.h
===================================================================
--- trunk/bibdesk/BDSKSearchGroup.h 2025-04-24 15:59:23 UTC (rev 29193)
+++ trunk/bibdesk/BDSKSearchGroup.h 2025-04-25 16:30:07 UTC (rev 29194)
@@ -42,6 +42,7 @@
NS_ASSUME_NONNULL_BEGIN
extern NSString *BDSKSearchGroupEntrez;
+extern NSString *BDSKSearchGroupSRU;
extern NSString *BDSKSearchGroupZoom;
extern NSString *BDSKSearchGroupISI;
extern NSString *BDSKSearchGroupDBLP;
Modified: trunk/bibdesk/BDSKSearchGroup.m
===================================================================
--- trunk/bibdesk/BDSKSearchGroup.m 2025-04-24 15:59:23 UTC (rev 29193)
+++ trunk/bibdesk/BDSKSearchGroup.m 2025-04-25 16:30:07 UTC (rev 29194)
@@ -45,6 +45,7 @@
#import "BDSKServerInfo.h"
#import "BDSKISIGroupServer.h"
#import "BDSKDBLPGroupServer.h"
+#import "BDSKSRUGroupServer.h"
#import "BDSKGroup+Scripting.h"
#import "BibItem.h"
#import "BDSKStringConstants.h"
@@ -54,6 +55,7 @@
#import "NSFileManager_BDSKExtensions.h"
NSString *BDSKSearchGroupEntrez = @"entrez";
+NSString *BDSKSearchGroupSRU = @"sru";
NSString *BDSKSearchGroupZoom = @"zoom";
NSString *BDSKSearchGroupISI = @"isi";
NSString *BDSKSearchGroupDBLP = @"dblp";
@@ -386,6 +388,11 @@
aName = value;
} else if ([key isEqualToString:@"database"]) {
aDatabase = value;
+ } else if ([key isEqualToString:@"type"]) {
+ if ([value isCaseInsensitiveEqual:BDSKSearchGroupSRU])
+ aType = BDSKSearchGroupSRU;
+ else if ([value isCaseInsensitiveEqual:BDSKSearchGroupZoom])
+ aType = BDSKSearchGroupZoom;
} else {
if ([key isEqualToString:@"removeDiacritics"] || [key
isEqualToString:@"lite"]) {
if ([value boolValue] == NO) continue;
@@ -405,6 +412,9 @@
[dictionary setValue:aHost forKey:@"host"];
[dictionary setValue:aPort forKey:@"port"];
[dictionary setValue:options forKey:@"options"];
+ } else if ([aType isEqualToString:BDSKSearchGroupSRU]) {
+ [dictionary setValue:aHost forKey:@"host"];
+ [dictionary setValue:aPort forKey:@"port"];
} else if ([aType isEqualToString:BDSKSearchGroupISI] && [options count] >
0) {
[dictionary setValue:options forKey:@"options"];
}
@@ -423,6 +433,8 @@
serverClass = [BDSKISIGroupServer class];
else if ([aType isEqualToString:BDSKSearchGroupDBLP])
serverClass = [BDSKDBLPGroupServer class];
+ else if ([aType isEqualToString:BDSKSearchGroupSRU])
+ serverClass = [BDSKSRUGroupServer class];
else
BDSKASSERT_NOT_REACHED("unknown search group type");
return [[serverClass alloc] initWithGroup:group serverInfo:info];
Modified: trunk/bibdesk/BDSKSearchGroupSheetController.h
===================================================================
--- trunk/bibdesk/BDSKSearchGroupSheetController.h 2025-04-24 15:59:23 UTC
(rev 29193)
+++ trunk/bibdesk/BDSKSearchGroupSheetController.h 2025-04-25 16:30:07 UTC
(rev 29194)
@@ -112,7 +112,9 @@
@property (nonatomic, getter=isEditable) BOOL editable;
@property (nonatomic, readonly, getter=isZoom) BOOL zoom;
@property (nonatomic, readonly, getter=isISI) BOOL ISI;
+@property (nonatomic, readonly, getter=isSRU) BOOL SRU;
@property (nonatomic, readonly, getter=isZoomOrISI) BOOL zoomOrISI;
+@property (nonatomic, readonly, getter=isZoomOrSRU) BOOL zoomOrSRU;
@property (nonatomic, strong) NSString *type;
Modified: trunk/bibdesk/BDSKSearchGroupSheetController.m
===================================================================
--- trunk/bibdesk/BDSKSearchGroupSheetController.m 2025-04-24 15:59:23 UTC
(rev 29193)
+++ trunk/bibdesk/BDSKSearchGroupSheetController.m 2025-04-25 16:30:07 UTC
(rev 29194)
@@ -54,13 +54,13 @@
@implementation BDSKSearchGroupSheetController
@synthesize serverPopup, nameField, addressField, portField, databaseField,
passwordField, userField, syntaxPopup, encodingComboBox,
removeDiacriticsButton, liteButton, editButton, addRemoveButton, serverView,
revealButton, okButton, cancelButton, bottomConstraint, objectController,
custom, editable;
-@dynamic zoom, ISI, zoomOrISI, typeTag, databases, serverInfo, undoManager;
+@dynamic zoom, ISI, SRU, zoomOrISI, zoomOrSRU, typeTag, databases, serverInfo,
undoManager;
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([[NSSet setWithObjects:@"type", nil] containsObject:key])
keyPaths = [keyPaths setByAddingObjectsFromSet:[NSSet
setWithObjects:@"serverInfo", nil]];
- else if ([[NSSet setWithObjects:@"typeTag", @"zoom", @"ISI", @"zoomOrISI",
@"databases", nil] containsObject:key])
+ else if ([[NSSet setWithObjects:@"typeTag", @"zoom", @"ISI", @"SRU",
@"zoomOrISI", @"zoomOrSRU", @"databases", nil] containsObject:key])
keyPaths = [keyPaths setByAddingObjectsFromSet:[NSSet
setWithObjects:@"type", nil]];
return keyPaths;
}
@@ -314,8 +314,12 @@
- (BOOL)isISI { return [serverInfo isISI]; }
+- (BOOL)isSRU { return [serverInfo isSRU]; }
+
- (BOOL)isZoomOrISI { return [serverInfo isZoom] || [serverInfo isISI]; }
+- (BOOL)isZoomOrSRU { return [serverInfo isZoom] || [serverInfo isSRU]; }
+
- (BDSKServerInfo *)serverInfo { return serverInfo; }
- (void)setServerInfo:(BDSKServerInfo *)info;
@@ -345,6 +349,7 @@
case BDSKServerTypeZoom: [self setType:BDSKSearchGroupZoom]; break;
case BDSKServerTypeISI: [self setType:BDSKSearchGroupISI]; break;
case BDSKServerTypeDBLP: [self setType:BDSKSearchGroupDBLP]; break;
+ case BDSKServerTypeSRU: [self setType:BDSKSearchGroupSRU]; break;
default: BDSKASSERT_NOT_REACHED("Unknown search type tag");
}
}
@@ -359,6 +364,7 @@
return entrezDatabases;
}
case BDSKServerTypeZoom:
+ case BDSKServerTypeSRU:
return @[];
case BDSKServerTypeISI:
{
Modified: trunk/bibdesk/BDSKServerInfo.h
===================================================================
--- trunk/bibdesk/BDSKServerInfo.h 2025-04-24 15:59:23 UTC (rev 29193)
+++ trunk/bibdesk/BDSKServerInfo.h 2025-04-25 16:30:07 UTC (rev 29194)
@@ -44,7 +44,8 @@
BDSKServerTypeEntrez,
BDSKServerTypeZoom,
BDSKServerTypeDBLP,
- BDSKServerTypeISI
+ BDSKServerTypeISI,
+ BDSKServerTypeSRU
};
@class BDSKReadWriteLock;
@@ -86,6 +87,7 @@
@property (nonatomic, readonly, getter=isZoom) BOOL zoom;
@property (nonatomic, readonly, getter=isISI) BOOL ISI;
@property (nonatomic, readonly, getter=isDBLP) BOOL DBLP;
+@property (nonatomic, readonly, getter=isSRU) BOOL SRU;
@property (nonatomic, readonly) BDSKServerType serverType;
Modified: trunk/bibdesk/BDSKServerInfo.m
===================================================================
--- trunk/bibdesk/BDSKServerInfo.m 2025-04-24 15:59:23 UTC (rev 29193)
+++ trunk/bibdesk/BDSKServerInfo.m 2025-04-25 16:30:07 UTC (rev 29194)
@@ -81,7 +81,7 @@
@implementation BDSKServerInfo
@synthesize type, name, database;
-@dynamic dictionaryValue, host, port, username, recordSyntax, resultEncoding,
queryConfig, removeDiacritics, lite, options, entrez, zoom, ISI, DBLP,
serverType, URLValue;
+@dynamic dictionaryValue, host, port, username, recordSyntax, resultEncoding,
queryConfig, removeDiacritics, lite, options, entrez, zoom, ISI, DBLP, SRU,
serverType, URLValue;
+ (BOOL)accessInstanceVariablesDirectly { return NO; }
@@ -88,12 +88,13 @@
+ (instancetype)defaultServerInfoWithType:(NSString *)aType;
{
BOOL isZoom = [aType isEqualToString:BDSKSearchGroupZoom];
+ BOOL isSRU = [aType isEqualToString:BDSKSearchGroupSRU];
return [[[self class] alloc] initWithType:aType
name:DEFAULT_NAME
database:DEFAULT_DATABASE
- host:isZoom ? DEFAULT_HOST : nil
- port:isZoom ? DEFAULT_PORT : nil
+ host:isZoom || isSRU ? DEFAULT_HOST :
nil
+ port:isZoom || isSRU ? DEFAULT_PORT :
nil
options:isZoom ? @{} : nil];
}
@@ -188,9 +189,12 @@
isEqualOrBothNil([self database], [other database]) == NO)
isEqual = NO;
else if ([self isZoom])
- isEqual = isEqualOrBothNil([self host], [other host]) &&
- isEqualOrBothNil([self port], [(BDSKServerInfo *)other
port]) &&
+ isEqual = isEqualOrBothNil([self host], [other host]) &&
+ isEqualOrBothNil([self port], [(BDSKServerInfo *)other
port]) &&
isEqualOrBothEmpty(options, [(BDSKServerInfo *)other
options]);
+ else if ([self isSRU])
+ isEqual = isEqualOrBothNil([self host], [other host]) &&
+ isEqualOrBothNil([self port], [(BDSKServerInfo *)other
port]);
else if ([self isISI])
isEqual = isEqualOrBothEmpty(options, [(BDSKServerInfo *)other
options]);
return isEqual;
@@ -199,7 +203,7 @@
- (NSUInteger)hash {
NSUInteger prime = 31;
NSUInteger hash = prime * [[self type] hash] + [[self database] hash];
- if ([self isZoom]) {
+ if ([self isZoom] || [self isSRU]) {
hash = prime * hash + [[self host] hash];
hash = prime * hash + [[self port] hash];
}
@@ -220,6 +224,9 @@
[info setValue:[self host] forKey:HOST_KEY];
[info setValue:[self port] forKey:PORT_KEY];
[info setValue:[self options] forKey:OPTIONS_KEY];
+ } else if ([self isSRU]) {
+ [info setValue:[self host] forKey:HOST_KEY];
+ [info setValue:[self port] forKey:PORT_KEY];
} else if ([self isISI] && [options count] > 0) {
[info setValue:[self options] forKey:OPTIONS_KEY];
}
@@ -226,9 +233,9 @@
return info;
}
-- (NSString *)host { return [self isZoom] ? host : nil; }
+- (NSString *)host { return [self isZoom] || [self isSRU] ? host : nil; }
-- (NSString *)port { return [self isZoom] ? port : nil; }
+- (NSString *)port { return [self isZoom] || [self isSRU] ? port : nil; }
- (NSString *)username { return [options objectForKey:USERNAME_KEY]; }
@@ -250,6 +257,7 @@
- (BOOL)isZoom { return [[self type] isEqualToString:BDSKSearchGroupZoom]; }
- (BOOL)isISI { return [[self type] isEqualToString:BDSKSearchGroupISI]; }
- (BOOL)isDBLP { return [[self type] isEqualToString:BDSKSearchGroupDBLP]; }
+- (BOOL)isSRU { return [[self type] isEqualToString:BDSKSearchGroupSRU]; }
- (BDSKServerType)serverType {
if ([self isEntrez])
@@ -260,6 +268,8 @@
return BDSKServerTypeISI;
if ([self isDBLP])
return BDSKServerTypeDBLP;
+ if ([self isSRU])
+ return BDSKServerTypeSRU;
BDSKASSERT_NOT_REACHED("Unknown search type");
return BDSKServerTypeEntrez;
}
@@ -337,7 +347,7 @@
NSString *username = [self username];
if (username)
[components setPercentEncodedUser:escapeUser(username)];
- if ([self isZoom]) {
+ if ([self isZoom] || [self isSRU]) {
[components setPercentEncodedHost:escapeHost([self host])];
[components setPort:[NSNumber numberWithInteger:[[self port]
integerValue]]];
} else {
@@ -357,6 +367,8 @@
[components setPercentEncodedQuery:[query
componentsJoinedByString:@"&"]];
} else if ([self isISI] && [self isLite]) {
[components setPercentEncodedQuery:@"lite=1"];
+ } else if ([self isSRU]) {
+ [components setPercentEncodedQuery:@"type=sru"];
}
NSURL *url = [components URL];
return url;
@@ -396,6 +408,11 @@
[self setPort:DEFAULT_PORT];
password = nil;
options = [[NSMutableDictionary alloc] init];
+ } else if ([self isSRU]) {
+ if (host == nil)
+ [self setHost:DEFAULT_HOST];
+ if (port == nil)
+ [self setPort:DEFAULT_PORT];
} else {
password = nil;
options = nil;
@@ -495,7 +512,7 @@
- (BOOL)validateHost:(id *)value error:(NSError **)error {
NSString *string = *value;
- if ([self isZoom]) {
+ if ([self isZoom] || [self isSRU]) {
NSRange range = [string rangeOfString:@"://"];
if(range.location != NSNotFound){
// ZOOM gets confused when the host has a protocol
Modified: trunk/bibdesk/Base.lproj/BDSKSearchGroupSheet.xib
===================================================================
--- trunk/bibdesk/Base.lproj/BDSKSearchGroupSheet.xib 2025-04-24 15:59:23 UTC
(rev 29193)
+++ trunk/bibdesk/Base.lproj/BDSKSearchGroupSheet.xib 2025-04-25 16:30:07 UTC
(rev 29194)
@@ -130,7 +130,7 @@
<color key="backgroundColor"
name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2"
name="hidden" keyPath="zoom" id="960">
+ <binding destination="-2"
name="hidden" keyPath="zoomOrSRU" id="mrZ-fQ-Vvk">
<dictionary key="options">
<string
key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
@@ -145,7 +145,7 @@
<color key="backgroundColor"
name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2"
name="hidden" keyPath="zoom" id="958">
+ <binding destination="-2"
name="hidden" keyPath="zoomOrSRU" id="fKC-PK-0y5">
<dictionary key="options">
<string
key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
@@ -276,6 +276,11 @@
<connections>
<accessibilityConnection
property="title" destination="191" id="525"/>
<binding destination="-2"
name="enabled" keyPath="editable" id="468"/>
+ <binding destination="-2"
name="hidden" keyPath="zoomOrSRU" previousBinding="979" id="zmn-bc-vkQ">
+ <dictionary key="options">
+ <string
key="NSValueTransformerName">NSNegateBoolean</string>
+ </dictionary>
+ </binding>
<binding destination="569"
name="value" keyPath="selection.port" id="578">
<dictionary key="options">
<integer
key="NSConditionallySetsEditable" value="0"/>
@@ -291,11 +296,6 @@
<integer
key="NSNullPlaceholder" value="-1"/>
</dictionary>
</binding>
- <binding destination="-2"
name="hidden" keyPath="zoom" previousBinding="979" id="980">
- <dictionary key="options">
- <string
key="NSValueTransformerName">NSNegateBoolean</string>
- </dictionary>
- </binding>
<outlet property="nextKeyView"
destination="201" id="293"/>
</connections>
</textField>
@@ -376,6 +376,11 @@
<connections>
<accessibilityConnection
property="title" destination="196" id="524"/>
<binding destination="-2"
name="enabled" keyPath="editable" id="480"/>
+ <binding destination="-2"
name="hidden" keyPath="zoomOrSRU" previousBinding="977" id="XIN-vT-kNF">
+ <dictionary key="options">
+ <string
key="NSValueTransformerName">NSNegateBoolean</string>
+ </dictionary>
+ </binding>
<binding destination="569"
name="value" keyPath="selection.host" id="576">
<dictionary key="options">
<integer
key="NSConditionallySetsEditable" value="0"/>
@@ -391,11 +396,6 @@
<integer
key="NSNullPlaceholder" value="-1"/>
</dictionary>
</binding>
- <binding destination="-2"
name="hidden" keyPath="zoom" previousBinding="977" id="978">
- <dictionary key="options">
- <string
key="NSValueTransformerName">NSNegateBoolean</string>
- </dictionary>
- </binding>
<outlet property="nextKeyView"
destination="198" id="212"/>
</connections>
</textField>
Modified: trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj
===================================================================
--- trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj 2025-04-24 15:59:23 UTC
(rev 29193)
+++ trunk/bibdesk/Bibdesk.xcodeproj/project.pbxproj 2025-04-25 16:30:07 UTC
(rev 29194)
@@ -469,6 +469,8 @@
CE3B5E7D09CEDE470017D339 /* BDSKMacroResolver.m in Sources */ =
{isa = PBXBuildFile; fileRef = CE3B5E7B09CEDE470017D339 /* BDSKMacroResolver.m
*/; };
CE3B682B09D1B0190017D339 /* BDSKImagePopUpButton.m in Sources
*/ = {isa = PBXBuildFile; fileRef = CE3B682709D1B0190017D339 /*
BDSKImagePopUpButton.m */; };
CE3B682D09D1B0190017D339 /* BDSKImagePopUpButtonCell.m in
Sources */ = {isa = PBXBuildFile; fileRef = CE3B682909D1B0190017D339 /*
BDSKImagePopUpButtonCell.m */; };
+ CE3D27C82DBB85AA002EA644 /* BDSKSRUGroupServer.h in Headers */
= {isa = PBXBuildFile; fileRef = CE3D27C62DBB85AA002EA644 /*
BDSKSRUGroupServer.h */; };
+ CE3D27C92DBB85AA002EA644 /* BDSKSRUGroupServer.m in Sources */
= {isa = PBXBuildFile; fileRef = CE3D27C72DBB85AA002EA644 /*
BDSKSRUGroupServer.m */; };
CE4241360D0EAE0B00F824E7 /* BDSKEditorTableView.m in Sources */
= {isa = PBXBuildFile; fileRef = CE4241340D0EAE0B00F824E7 /*
BDSKEditorTableView.m */; };
CE4241450D0EAEFE00F824E7 /* BDSKEditorTextField.m in Sources */
= {isa = PBXBuildFile; fileRef = CE4241430D0EAEFE00F824E7 /*
BDSKEditorTextField.m */; };
CE424A450D0F123500F824E7 /* BDSKCompletionServerProtocol.h in
Headers */ = {isa = PBXBuildFile; fileRef = CE3A0BD50B1634D500233208 /*
BDSKCompletionServerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1545,6 +1547,8 @@
CE3B682709D1B0190017D339 /* BDSKImagePopUpButton.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= BDSKImagePopUpButton.m; sourceTree = "<group>"; };
CE3B682809D1B0190017D339 /* BDSKImagePopUpButtonCell.h */ =
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
path = BDSKImagePopUpButtonCell.h; sourceTree = "<group>"; };
CE3B682909D1B0190017D339 /* BDSKImagePopUpButtonCell.m */ =
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.c.objc; path = BDSKImagePopUpButtonCell.m; sourceTree = "<group>"; };
+ CE3D27C62DBB85AA002EA644 /* BDSKSRUGroupServer.h */ = {isa =
PBXFileReference; lastKnownFileType = sourcecode.c.h; path =
BDSKSRUGroupServer.h; sourceTree = "<group>"; };
+ CE3D27C72DBB85AA002EA644 /* BDSKSRUGroupServer.m */ = {isa =
PBXFileReference; lastKnownFileType = sourcecode.c.objc; path =
BDSKSRUGroupServer.m; sourceTree = "<group>"; };
CE3D8DA0125E69BB00AE0232 /* de */ = {isa = PBXFileReference;
fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path =
de.lproj/BibTeXKeys.strings; sourceTree = "<group>"; };
CE3D8DA5125E69BB00AE0232 /* de */ = {isa = PBXFileReference;
lastKnownFileType = text.rtf; name = de; path = de.lproj/Credits.rtf;
sourceTree = "<group>"; };
CE3D8DA9125E69BB00AE0232 /* de */ = {isa = PBXFileReference;
fileEncoding = 10; lastKnownFileType = text.plist.strings; name = de; path =
de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -3171,6 +3175,8 @@
F94DB0F70B3E2FA1006F37A2 /* BDSKSearchGroup.m
*/,
F92EF32109E6242100A244D0 /* BDSKSharedGroup.m
*/,
CEFDBDBC0AEA86BA009EE99D /* BDSKSmartGroup.m */,
+ CE3D27C62DBB85AA002EA644 /*
BDSKSRUGroupServer.h */,
+ CE3D27C72DBB85AA002EA644 /*
BDSKSRUGroupServer.m */,
CEFDBDC40AEA86F0009EE99D /* BDSKStaticGroup.m
*/,
F9F5ECD00AE5E7C8007EBB31 /* BDSKURLGroup.m */,
4575382B0B70170D00C0E49B /* BDSKWebGroup.m */,
@@ -3762,6 +3768,7 @@
CE2A09F9224599E100A8F31C /*
BDSKFileContentSearchController.h in Headers */,
CE1C94E926A9CDFB00EF17E8 /*
BDSKGroupTextFieldCell.h in Headers */,
CE2A0A46224599F600A8F31C /*
BDSKPreferenceWindow.h in Headers */,
+ CE3D27C82DBB85AA002EA644 /*
BDSKSRUGroupServer.h in Headers */,
CE2A0A9722459A3600A8F31C /* BDSKTypeTemplate.h
in Headers */,
CE2A0A3A224599F600A8F31C /* BDSKOwnerProtocol.h
in Headers */,
CE2A0A4C224599F600A8F31C /*
BDSKPubMedXMLParser.h in Headers */,
@@ -5022,6 +5029,7 @@
CE2F056911B517E9001B0AE0 /*
BDSKOpenAccessoryViewController.m in Sources */,
CEFEF0ED11C23F1F0050350D /*
BDSKCompletionServer.m in Sources */,
CEFE21321259E6CB00DAD553 /*
BDSKSearchGroupServerManager.m in Sources */,
+ CE3D27C92DBB85AA002EA644 /*
BDSKSRUGroupServer.m in Sources */,
CE044A4512667EB500CE55C4 /*
BDSKDownloadManager.m in Sources */,
CEF7F42712743BCC00B20881 /* BDSKWebView.m in
Sources */,
CE03C0CB127D751D00F62F51 /*
BDSKWebViewModalDialogController.m in Sources */,
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit