mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-24 03:44:33 +00:00
625 lines
18 KiB
Objective-C
625 lines
18 KiB
Objective-C
/* Implementation of class NSFontCollection
|
|
Copyright (C) 2019, 2020 Free Software Foundation, Inc.
|
|
|
|
By: Gregory John Casamento
|
|
Date: Tue Dec 10 11:51:33 EST 2019
|
|
|
|
Author: Fred Kiefer <fredkiefer@gmx.de>
|
|
Date: March 2020
|
|
|
|
This file is part of the GNUstep Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110 USA.
|
|
*/
|
|
|
|
#import <Foundation/NSArray.h>
|
|
#import <Foundation/NSData.h>
|
|
#import <Foundation/NSDebug.h>
|
|
#import <Foundation/NSDictionary.h>
|
|
#import <Foundation/NSError.h>
|
|
#import <Foundation/NSException.h>
|
|
#import <Foundation/NSFileManager.h>
|
|
#import <Foundation/NSKeyedArchiver.h>
|
|
#import <Foundation/NSLocale.h>
|
|
#import <Foundation/NSLock.h>
|
|
#import <Foundation/NSPathUtilities.h>
|
|
#import <Foundation/NSString.h>
|
|
#import <Foundation/NSValue.h>
|
|
|
|
#import <AppKit/NSFontCollection.h>
|
|
#import <AppKit/NSFontDescriptor.h>
|
|
#import <GNUstepGUI/GSFontInfo.h>
|
|
|
|
static NSMutableDictionary *_availableFontCollections = nil;
|
|
static NSLock *_fontCollectionLock = nil;
|
|
|
|
/*
|
|
* Private functions...
|
|
*/
|
|
@interface NSFontCollection (Private)
|
|
|
|
+ (NSFontCollection *) _readFileAtPath: (NSString *)path;
|
|
+ (void) _loadAvailableFontCollections;
|
|
- (BOOL) _writeToFileAtPath: (NSString *)path;
|
|
- (BOOL) _writeToFile;
|
|
- (BOOL) _removeFile;
|
|
- (NSMutableDictionary *) _fontCollectionDictionary;
|
|
- (void) _setFontCollectionDictionary: (NSMutableDictionary *)dict;
|
|
- (void) _setQueryDescriptors: (NSArray *)queryDescriptors;
|
|
- (void) _setFullFileName: (NSString *)fn;
|
|
- (NSString *) _fullFileName;
|
|
- (void) _setName: (NSString *)n;
|
|
- (NSString *) _name;
|
|
@end
|
|
|
|
/*
|
|
* Private functions...
|
|
*/
|
|
@implementation NSFontCollection (Private)
|
|
|
|
/**
|
|
* Load all font collections....
|
|
*/
|
|
+ (void) _loadAvailableFontCollections
|
|
{
|
|
[_fontCollectionLock lock];
|
|
|
|
if (_availableFontCollections != nil)
|
|
{
|
|
// Nothing to do ... already loaded
|
|
[_fontCollectionLock unlock];
|
|
}
|
|
else
|
|
{
|
|
NSString *dir = nil;
|
|
NSEnumerator *e = nil;
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
|
|
|
// Create the global array of font collections...
|
|
_availableFontCollections = [[NSMutableDictionary alloc] init];
|
|
|
|
/*
|
|
* Load font lists found in standard paths into the array
|
|
*/
|
|
e = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
|
NSAllDomainsMask, YES) objectEnumerator];
|
|
|
|
while ((dir = (NSString *)[e nextObject]))
|
|
{
|
|
BOOL flag;
|
|
NSDirectoryEnumerator *de = nil;
|
|
NSString *file = nil;
|
|
|
|
dir = [dir stringByAppendingPathComponent: @"FontCollections"];
|
|
if (![fm fileExistsAtPath: dir isDirectory: &flag] || !flag)
|
|
{
|
|
// Only process existing directories
|
|
continue;
|
|
}
|
|
|
|
de = [fm enumeratorAtPath: dir];
|
|
while ((file = [de nextObject]))
|
|
{
|
|
if ([[file pathExtension] isEqualToString: @"collection"])
|
|
{
|
|
NSString *name = [file stringByDeletingPathExtension];
|
|
NSString *path = [dir stringByAppendingPathComponent: file];
|
|
NSFontCollection *newCollection = [self _readFileAtPath: path];
|
|
|
|
if (newCollection != nil && name != nil)
|
|
{
|
|
[newCollection _setFullFileName: path];
|
|
[newCollection _setName: name];
|
|
[_availableFontCollections setObject: newCollection
|
|
forKey: name];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[_fontCollectionLock unlock];
|
|
}
|
|
}
|
|
|
|
+ (NSFontCollection *) _readFileAtPath: (NSString *)path
|
|
{
|
|
NSData *d = [NSData dataWithContentsOfFile: path];
|
|
NSKeyedUnarchiver *u = [[NSKeyedUnarchiver alloc] initForReadingWithData: d];
|
|
NSFontCollection *fc = [[NSFontCollection alloc] initWithCoder: u];
|
|
|
|
RELEASE(u);
|
|
|
|
return AUTORELEASE(fc);
|
|
}
|
|
|
|
/*
|
|
* Writing and Removing Files
|
|
*/
|
|
- (BOOL) _writeToFileAtPath: (NSString *)path
|
|
{
|
|
BOOL success = NO;
|
|
NSMutableData *m = [[NSMutableData alloc] initWithCapacity: 1024];
|
|
NSKeyedArchiver *a = [[NSKeyedArchiver alloc] initForWritingWithMutableData: m];
|
|
|
|
[self encodeWithCoder: a];
|
|
[a finishEncoding];
|
|
RELEASE(a);
|
|
|
|
// Write the file....
|
|
NSDebugLLog(@"NSFontCollection", @"Writing to %@", path);
|
|
success = [m writeToFile: path atomically: YES];
|
|
RELEASE(m);
|
|
return success;
|
|
}
|
|
|
|
- (BOOL) _writeToFile
|
|
{
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
|
BOOL success = NO;
|
|
NSString *path = [self _fullFileName];
|
|
|
|
/*
|
|
* We need to initialize before saving, to avoid the new file being
|
|
* counted as a different collection thus making it appear twice
|
|
*/
|
|
[NSFontCollection _loadAvailableFontCollections];
|
|
|
|
if (path == nil)
|
|
{
|
|
// Find library....
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
|
NSUserDomainMask, YES);
|
|
|
|
if ([paths count] == 0)
|
|
{
|
|
NSLog(@"Failed to find Library directory for user");
|
|
return NO;
|
|
}
|
|
|
|
path = [[paths objectAtIndex: 0]
|
|
stringByAppendingPathComponent: @"FontCollections"];
|
|
if ([fm fileExistsAtPath: path] == NO)
|
|
{
|
|
if ([fm createDirectoryAtPath: path
|
|
withIntermediateDirectories: YES
|
|
attributes: nil
|
|
error: NULL])
|
|
{
|
|
NSDebugLLog(@"NSFontCollection", @"Created standard directory %@", path);
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"Failed attempt to create directory %@", path);
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
NSDebugLLog(@"NSFontCollection", @"Font collection name = %@", [self _name]);
|
|
path = [path stringByAppendingPathComponent:
|
|
[[self _name] stringByAppendingPathExtension: @"collection"]];
|
|
|
|
[self _setFullFileName: path];
|
|
}
|
|
|
|
// Create the archive...
|
|
success = [self _writeToFileAtPath: path];
|
|
if (success)
|
|
{
|
|
[_fontCollectionLock lock];
|
|
if ([[_availableFontCollections allValues] containsObject: self] == NO)
|
|
{
|
|
[_availableFontCollections setObject: self forKey: [self _name]];
|
|
}
|
|
[_fontCollectionLock unlock];
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
- (BOOL) _removeFile
|
|
{
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
|
BOOL isDir;
|
|
NSString *path = [self _fullFileName];
|
|
BOOL result = NO;
|
|
|
|
/*
|
|
* We need to initialize before saving, to avoid the new file being
|
|
* counted as a different collection thus making it appear twice
|
|
*/
|
|
[NSFontCollection _loadAvailableFontCollections];
|
|
|
|
if (path == nil)
|
|
{
|
|
// the standard path for saving font collections
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
|
NSUserDomainMask, YES);
|
|
if ([paths count] == 0)
|
|
{
|
|
NSLog(@"Failed to find Library directory for user");
|
|
return NO;
|
|
}
|
|
path = [[[[paths objectAtIndex: 0]
|
|
stringByAppendingPathComponent: @"FontCollections"]
|
|
stringByAppendingPathComponent: [self _name]]
|
|
stringByAppendingPathExtension: @"collection"];
|
|
}
|
|
|
|
if (![fm fileExistsAtPath: path isDirectory: &isDir] || isDir)
|
|
{
|
|
NSLog(@"Failed to find font collection file to delete");
|
|
return NO;
|
|
}
|
|
else
|
|
{
|
|
// Remove the file
|
|
result = [[NSFileManager defaultManager] removeFileAtPath: path
|
|
handler: nil];
|
|
|
|
// Remove the collection from the global list of font collections
|
|
[_fontCollectionLock lock];
|
|
[_availableFontCollections removeObjectForKey: [self _name]];
|
|
[_fontCollectionLock unlock];
|
|
|
|
// Reset file name
|
|
[self _setFullFileName: nil];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (NSMutableDictionary *) _fontCollectionDictionary
|
|
{
|
|
return _fontCollectionDictionary;
|
|
}
|
|
|
|
- (void) _setFontCollectionDictionary: (NSMutableDictionary *)dict
|
|
{
|
|
ASSIGNCOPY(_fontCollectionDictionary, dict);
|
|
}
|
|
|
|
- (void) _setQueryDescriptors: (NSArray *)queryDescriptors
|
|
{
|
|
return [_fontCollectionDictionary setObject: queryDescriptors
|
|
forKey: @"NSFontCollectionFontDescriptors"];
|
|
}
|
|
|
|
- (NSMutableDictionary *) _fontCollectionAttributes
|
|
{
|
|
NSMutableDictionary *attrs = [_fontCollectionDictionary objectForKey:
|
|
@"NSFontCollectionAttributes"];
|
|
|
|
if (attrs == nil)
|
|
{
|
|
attrs = [NSMutableDictionary dictionary];
|
|
[_fontCollectionDictionary setObject: attrs
|
|
forKey: @"NSFontCollectionAttributes"];
|
|
}
|
|
return attrs;
|
|
}
|
|
|
|
- (void) _setName: (NSString *)n
|
|
{
|
|
[[self _fontCollectionAttributes] setObject: n
|
|
forKey: @"NSFontCollectionName"];
|
|
}
|
|
|
|
- (NSString *) _name
|
|
{
|
|
return [[self _fontCollectionAttributes] objectForKey: @"NSFontCollectionName"];
|
|
}
|
|
|
|
- (void) _setFullFileName: (NSString *)fn
|
|
{
|
|
[[self _fontCollectionAttributes] setObject: fn
|
|
forKey: @"NSFontCollectionFileName"];
|
|
}
|
|
|
|
- (NSString *) _fullFileName
|
|
{
|
|
return [[self _fontCollectionAttributes] objectForKey: @"NSFontCollectionFileName"];
|
|
}
|
|
|
|
@end
|
|
|
|
/*
|
|
* NSFontCollection
|
|
*/
|
|
@implementation NSFontCollection
|
|
|
|
+ (void) initialize
|
|
{
|
|
if (self == [NSFontCollection class])
|
|
{
|
|
[self _loadAvailableFontCollections];
|
|
}
|
|
}
|
|
|
|
// Initializers...
|
|
- (instancetype) initWithDescriptors: (NSArray *)queryDescriptors
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
_fontCollectionDictionary = [[NSMutableDictionary alloc] initWithCapacity: 10];
|
|
[self _setQueryDescriptors: queryDescriptors];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype) init
|
|
{
|
|
return [self initWithDescriptors: [NSArray array]];
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
RELEASE(_fontCollectionDictionary);
|
|
[super dealloc];
|
|
}
|
|
|
|
+ (NSFontCollection *) fontCollectionWithDescriptors: (NSArray *)queryDescriptors
|
|
{
|
|
NSFontCollection *fc = [[NSFontCollection alloc] initWithDescriptors: queryDescriptors];
|
|
return AUTORELEASE(fc);
|
|
}
|
|
|
|
+ (NSFontCollection *) fontCollectionWithAllAvailableDescriptors
|
|
{
|
|
NSFontCollection *fc = [_availableFontCollections objectForKey: NSFontCollectionAllFonts];
|
|
if (fc == nil)
|
|
{
|
|
NSDictionary *fa = [NSDictionary dictionary];
|
|
NSFontDescriptor *fd = [NSFontDescriptor fontDescriptorWithFontAttributes: fa];
|
|
fc = [self fontCollectionWithDescriptors: [NSArray arrayWithObject: fd]];
|
|
if (fc != nil)
|
|
{
|
|
[fc _setName: NSFontCollectionAllFonts];
|
|
[fc _writeToFile];
|
|
}
|
|
}
|
|
return fc;
|
|
}
|
|
|
|
+ (NSFontCollection *) fontCollectionWithLocale: (NSLocale *)locale
|
|
{
|
|
NSDictionary *fa = [NSDictionary dictionaryWithObject: [locale languageCode]
|
|
forKey: @"NSCTFontDesignLanguagesAttribute"];
|
|
NSFontDescriptor *fd = [NSFontDescriptor fontDescriptorWithFontAttributes: fa];
|
|
return [self fontCollectionWithDescriptors: [NSArray arrayWithObject: fd]];
|
|
}
|
|
|
|
+ (BOOL) showFontCollection: (NSFontCollection *)collection
|
|
withName: (NSFontCollectionName)name
|
|
visibility: (NSFontCollectionVisibility)visibility
|
|
error: (NSError **)error
|
|
{
|
|
[collection _setName: name];
|
|
return [collection _writeToFile];
|
|
}
|
|
|
|
+ (BOOL) hideFontCollectionWithName: (NSFontCollectionName)name
|
|
visibility: (NSFontCollectionVisibility)visibility
|
|
error: (NSError **)error
|
|
{
|
|
NSFontCollection *collection = [_availableFontCollections objectForKey: name];
|
|
|
|
return [collection _removeFile];
|
|
}
|
|
|
|
+ (BOOL) renameFontCollectionWithName: (NSFontCollectionName)aname
|
|
visibility: (NSFontCollectionVisibility)visibility
|
|
toName: (NSFontCollectionName)name
|
|
error: (NSError **)error
|
|
{
|
|
NSFontCollection *collection = [_availableFontCollections objectForKey: aname];
|
|
BOOL rv = [collection _removeFile];
|
|
|
|
if (rv == YES)
|
|
{
|
|
[collection _setName: name];
|
|
[collection _writeToFile];
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
+ (NSArray *) allFontCollectionNames
|
|
{
|
|
return [_availableFontCollections allKeys];
|
|
}
|
|
|
|
+ (NSFontCollection *) fontCollectionWithName: (NSFontCollectionName)name
|
|
{
|
|
NSFontCollection *fc = [_availableFontCollections objectForKey: name];
|
|
if (fc == nil)
|
|
{
|
|
fc = [[NSFontCollection alloc] init];
|
|
[fc _setName: name];
|
|
AUTORELEASE(fc);
|
|
}
|
|
return fc;
|
|
}
|
|
|
|
+ (NSFontCollection *) fontCollectionWithName: (NSFontCollectionName)name
|
|
visibility: (NSFontCollectionVisibility)visibility
|
|
{
|
|
return [self fontCollectionWithName: name];
|
|
}
|
|
|
|
// Descriptors
|
|
- (NSArray *) queryDescriptors
|
|
{
|
|
return [_fontCollectionDictionary objectForKey: @"NSFontCollectionFontDescriptors"];
|
|
}
|
|
|
|
- (NSArray *) exclusionDescriptors
|
|
{
|
|
return [_fontCollectionDictionary objectForKey: @"NSFontExclusionDescriptorAttributes"];
|
|
}
|
|
|
|
- (NSArray *) matchingDescriptors
|
|
{
|
|
return [self matchingDescriptorsWithOptions: nil];
|
|
}
|
|
|
|
- (NSArray *) matchingDescriptorsWithOptions: (NSDictionary *)options
|
|
{
|
|
return [self matchingDescriptorsForFamily: nil options: options];
|
|
}
|
|
|
|
- (NSArray *) matchingDescriptorsForFamily: (NSString *)family
|
|
{
|
|
return [self matchingDescriptorsForFamily: family options: nil];
|
|
}
|
|
|
|
- (NSArray *) matchingDescriptorsForFamily: (NSString *)family options: (NSDictionary *)options
|
|
{
|
|
GSFontEnumerator *fen = [GSFontEnumerator sharedEnumerator];
|
|
|
|
return [fen matchingDescriptorsForFamily: family
|
|
options: options
|
|
inclusion: [self queryDescriptors]
|
|
exculsion: [self exclusionDescriptors]];
|
|
}
|
|
|
|
- (instancetype) copyWithZone: (NSZone *)zone
|
|
{
|
|
NSFontCollection *fc = [[NSFontCollection allocWithZone: zone] init];
|
|
[fc _setFontCollectionDictionary: _fontCollectionDictionary];
|
|
return fc;
|
|
}
|
|
|
|
- (instancetype) mutableCopyWithZone: (NSZone *)zone
|
|
{
|
|
NSMutableFontCollection *fc = [[NSMutableFontCollection allocWithZone: zone] init];
|
|
|
|
[fc _setFontCollectionDictionary: [_fontCollectionDictionary mutableCopyWithZone: zone]];
|
|
|
|
return fc;
|
|
}
|
|
|
|
- (void) encodeWithCoder: (NSCoder *)coder
|
|
{
|
|
if ([coder allowsKeyedCoding])
|
|
{
|
|
[coder encodeObject: _fontCollectionDictionary
|
|
forKey: @"NSFontCollectionDictionary"];
|
|
}
|
|
else
|
|
{
|
|
[coder encodeObject: _fontCollectionDictionary];
|
|
}
|
|
}
|
|
|
|
- (instancetype) initWithCoder: (NSCoder *)coder
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
if ([coder allowsKeyedCoding])
|
|
{
|
|
ASSIGN(_fontCollectionDictionary,
|
|
[coder decodeObjectForKey: @"NSFontCollectionDictionary"]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[coder decodeValueOfObjCType: @encode(id) at: &_fontCollectionDictionary];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation NSMutableFontCollection
|
|
|
|
+ (NSMutableFontCollection *) fontCollectionWithDescriptors: (NSArray *)queryDescriptors
|
|
{
|
|
return [[NSFontCollection fontCollectionWithDescriptors: queryDescriptors] mutableCopy];
|
|
}
|
|
|
|
+ (NSMutableFontCollection *) fontCollectionWithAllAvailableDescriptors
|
|
{
|
|
return [[NSFontCollection fontCollectionWithAllAvailableDescriptors] mutableCopy];
|
|
}
|
|
|
|
+ (NSMutableFontCollection *) fontCollectionWithLocale: (NSLocale *)locale
|
|
{
|
|
return [[NSFontCollection fontCollectionWithLocale: locale] mutableCopy];
|
|
}
|
|
|
|
+ (NSMutableFontCollection *) fontCollectionWithName: (NSFontCollectionName)name
|
|
{
|
|
return [[NSFontCollection fontCollectionWithName: name] mutableCopy];
|
|
}
|
|
|
|
+ (NSMutableFontCollection *) fontCollectionWithName: (NSFontCollectionName)name
|
|
visibility: (NSFontCollectionVisibility)visibility
|
|
{
|
|
return [[NSFontCollection fontCollectionWithName: name visibility: visibility] mutableCopy];
|
|
}
|
|
|
|
- (NSArray *) queryDescriptors
|
|
{
|
|
return [super queryDescriptors];
|
|
}
|
|
|
|
- (void) setQueryDescriptors: (NSArray *)queryDescriptors
|
|
{
|
|
[super _setQueryDescriptors: [queryDescriptors mutableCopy]];
|
|
}
|
|
|
|
- (NSArray *) exclusionDescriptors
|
|
{
|
|
return [_fontCollectionDictionary objectForKey: @"NSFontExclusionDescriptorAttributes"];
|
|
}
|
|
|
|
- (void) setExclusionDescriptors: (NSArray *)exclusionDescriptors
|
|
{
|
|
[_fontCollectionDictionary setObject: [exclusionDescriptors mutableCopy]
|
|
forKey: @"NSFontExclusionDescriptorAttributes"];
|
|
|
|
}
|
|
|
|
- (void) addQueryForDescriptors: (NSArray *)descriptors
|
|
{
|
|
NSMutableArray *arr = [[self queryDescriptors] mutableCopy];
|
|
NSMutableArray *ed = [[self exclusionDescriptors] mutableCopy];
|
|
|
|
[ed removeObjectsInArray: descriptors];
|
|
[arr addObjectsFromArray: descriptors];
|
|
[self setQueryDescriptors: arr];
|
|
[self setExclusionDescriptors: ed];
|
|
RELEASE(arr);
|
|
RELEASE(ed);
|
|
}
|
|
|
|
- (void) removeQueryForDescriptors: (NSArray *)descriptors
|
|
{
|
|
NSMutableArray *arr = [[self queryDescriptors] mutableCopy];
|
|
NSMutableArray *ed = [[self exclusionDescriptors] mutableCopy];
|
|
|
|
[ed addObjectsFromArray: descriptors];
|
|
[arr removeObjectsInArray: descriptors];
|
|
[self setQueryDescriptors: arr];
|
|
[self setExclusionDescriptors: ed];
|
|
RELEASE(arr);
|
|
RELEASE(ed);
|
|
}
|
|
|
|
@end
|