Modernize several classes.
Use modern ObjC syntax. Use new Pasteboard APIs. Explicitly declare protocols.CQTexperiment
parent
730276a7e7
commit
c1da9a66e1
|
@ -11,16 +11,12 @@
|
||||||
@class PathNode;
|
@class PathNode;
|
||||||
@class PathWatcher;
|
@class PathWatcher;
|
||||||
|
|
||||||
@interface FileTreeDataSource : NSObject {
|
@interface FileTreeDataSource : NSObject <NSOutlineViewDataSource>
|
||||||
PathNode *rootNode;
|
|
||||||
|
@property(nonatomic, weak) IBOutlet NSOutlineView *outlineView;
|
||||||
IBOutlet NSPathControl *pathControl;
|
@property(nonatomic, weak) IBOutlet NSPathControl *pathControl;
|
||||||
IBOutlet PathWatcher *watcher;
|
@property(nonatomic, weak) IBOutlet PathWatcher *watcher;
|
||||||
IBOutlet NSOutlineView *outlineView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURL *)rootURL;
|
|
||||||
- (void)setRootURL:(NSURL *)rootURL;
|
|
||||||
- (void)changeURL:(NSURL *)rootURL;
|
- (void)changeURL:(NSURL *)rootURL;
|
||||||
|
|
||||||
- (void)reloadPathNode:(PathNode *)item;
|
- (void)reloadPathNode:(PathNode *)item;
|
||||||
|
|
|
@ -8,176 +8,159 @@
|
||||||
|
|
||||||
#import "FileTreeDataSource.h"
|
#import "FileTreeDataSource.h"
|
||||||
|
|
||||||
#import "DNDArrayController.h"
|
|
||||||
|
|
||||||
#import "DirectoryNode.h"
|
#import "DirectoryNode.h"
|
||||||
#import "PathWatcher.h"
|
#import "PathWatcher.h"
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
@implementation FileTreeDataSource
|
NSURL *defaultMusicDirectory() {
|
||||||
|
return [[NSFileManager defaultManager] URLForDirectory:NSMusicDirectory
|
||||||
+ (void)initialize
|
inDomain:NSUserDomainMask
|
||||||
{
|
appropriateForURL:nil
|
||||||
NSMutableDictionary *userDefaultsValuesDict = [NSMutableDictionary dictionary];
|
create:NO
|
||||||
|
error:nil];
|
||||||
[userDefaultsValuesDict setObject:[[NSURL fileURLWithPath:[@"~/Music" stringByExpandingTildeInPath]] absoluteString] forKey:@"fileTreeRootURL"];
|
|
||||||
|
|
||||||
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)awakeFromNib
|
@interface FileTreeDataSource()
|
||||||
{
|
|
||||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.fileTreeRootURL" options:0 context:nil];
|
|
||||||
|
|
||||||
[self setRootURL: [NSURL URLWithString:[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]]];
|
|
||||||
|
|
||||||
[pathControl setTarget:self];
|
@property NSURL *rootURL;
|
||||||
[pathControl setAction:@selector(pathControlAction:)];
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FileTreeDataSource {
|
||||||
|
PathNode *rootNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) observeValueForKeyPath:(NSString *)keyPath
|
+ (void)initialize {
|
||||||
ofObject:(id)object
|
NSString *path = [defaultMusicDirectory() absoluteString];
|
||||||
change:(NSDictionary *)change
|
NSDictionary *userDefaultsValuesDict = @{@"fileTreeRootURL": path};
|
||||||
context:(void *)context
|
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
||||||
{
|
|
||||||
DLog(@"File tree root URL: %@\n", [[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]);
|
|
||||||
if ([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
|
|
||||||
[self setRootURL:[NSURL URLWithString:[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]]];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)changeURL:(NSURL *)url
|
- (void)awakeFromNib {
|
||||||
{
|
[self.pathControl setTarget:self];
|
||||||
if (url != nil)
|
[self.pathControl setAction:@selector(pathControlAction:)];
|
||||||
{
|
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
|
||||||
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString] forKey:@"fileTreeRootURL"];
|
forKeyPath:@"values.fileTreeRootURL"
|
||||||
}
|
options:NSKeyValueObservingOptionNew |
|
||||||
|
NSKeyValueObservingOptionInitial
|
||||||
|
context:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pathControlAction:(id)sender
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||||
{
|
ofObject:(id)object
|
||||||
if ([pathControl clickedPathComponentCell] != nil && [[pathControl clickedPathComponentCell] URL] != nil)
|
change:(NSDictionary *)change
|
||||||
{
|
context:(void *)context {
|
||||||
[self changeURL:[[pathControl clickedPathComponentCell] URL]];
|
if ([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
|
||||||
}
|
NSString *url =
|
||||||
|
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"];
|
||||||
|
DLog(@"File tree root URL: %@\n", url);
|
||||||
|
self.rootURL = [NSURL URLWithString:url];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURL *)rootURL
|
- (void)changeURL:(NSURL *)url {
|
||||||
{
|
if (url != nil) {
|
||||||
return [rootNode URL];
|
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString]
|
||||||
|
forKey:@"fileTreeRootURL"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRootURL: (NSURL *)rootURL
|
- (void)pathControlAction:(id)sender {
|
||||||
{
|
NSPathControlItem *item = [self.pathControl clickedPathItem];
|
||||||
if (![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]])
|
if (item != nil && item.URL != nil) {
|
||||||
rootURL = [NSURL fileURLWithPath:[@"~/Music" stringByExpandingTildeInPath]];
|
[self changeURL:item.URL];
|
||||||
|
}
|
||||||
rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL];
|
|
||||||
|
|
||||||
[watcher setPath:[rootURL path]];
|
|
||||||
|
|
||||||
[self reloadPathNode:rootNode];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (PathNode *)nodeForPath:(NSString *)path
|
- (NSURL *)rootURL {
|
||||||
{
|
return [rootNode URL];
|
||||||
NSString *relativePath = [[path stringByReplacingOccurrencesOfString:[[[self rootURL] path] stringByAppendingString:@"/"]
|
|
||||||
withString:@""
|
|
||||||
options:NSAnchoredSearch
|
|
||||||
range:NSMakeRange(0, [path length])
|
|
||||||
] stringByStandardizingPath];
|
|
||||||
PathNode *node = rootNode;
|
|
||||||
DLog(@"Root | Relative | Path: %@ | %@ | %@",[[self rootURL] path], relativePath, path);
|
|
||||||
for (NSString *c in [relativePath pathComponents])
|
|
||||||
{
|
|
||||||
DLog(@"COMPONENT: %@", c);
|
|
||||||
BOOL found = NO;
|
|
||||||
for (PathNode *subnode in [node subpaths]) {
|
|
||||||
if ([[[[subnode URL] path] lastPathComponent] isEqualToString:c]) {
|
|
||||||
node = subnode;
|
|
||||||
found = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
DLog(@"Not found!");
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pathDidChange:(NSString *)path
|
- (void)setRootURL:(NSURL *)rootURL {
|
||||||
{
|
if (![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]]) {
|
||||||
DLog(@"PATH DID CHANGE: %@", path);
|
rootURL = defaultMusicDirectory();
|
||||||
//Need to find the corresponding node...and call [node reloadPath], then [self reloadPathNode:node]
|
}
|
||||||
PathNode *node = [self nodeForPath:path];
|
|
||||||
DLog(@"NODE IS: %@", node);
|
rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL];
|
||||||
[node updatePath];
|
|
||||||
[self reloadPathNode:node];
|
[self.watcher setPath:[rootURL path]];
|
||||||
|
|
||||||
|
[self reloadPathNode:rootNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
|
- (PathNode *)nodeForPath:(NSString *)path {
|
||||||
{
|
NSString *relativePath = [[path stringByReplacingOccurrencesOfString:[[[self rootURL] path] stringByAppendingString:@"/"]
|
||||||
PathNode *n = (item == nil ? rootNode : item);
|
withString:@""
|
||||||
|
options:NSAnchoredSearch
|
||||||
|
range:NSMakeRange(0, [path length])
|
||||||
|
] stringByStandardizingPath];
|
||||||
|
PathNode *node = rootNode;
|
||||||
|
DLog(@"Root | Relative | Path: %@ | %@ | %@", [[self rootURL] path], relativePath, path);
|
||||||
|
for (NSString *c in [relativePath pathComponents]) {
|
||||||
|
DLog(@"COMPONENT: %@", c);
|
||||||
|
BOOL found = NO;
|
||||||
|
for (PathNode *subnode in [node subpaths]) {
|
||||||
|
if ([[[[subnode URL] path] lastPathComponent] isEqualToString:c]) {
|
||||||
|
node = subnode;
|
||||||
|
found = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
DLog(@"Not found!");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pathDidChange:(NSString *)path {
|
||||||
|
DLog(@"PATH DID CHANGE: %@", path);
|
||||||
|
//Need to find the corresponding node...and call [node reloadPath], then [self reloadPathNode:node]
|
||||||
|
PathNode *node = [self nodeForPath:path];
|
||||||
|
DLog(@"NODE IS: %@", node);
|
||||||
|
[node updatePath];
|
||||||
|
[self reloadPathNode:node];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
|
||||||
|
PathNode *n = (item == nil ? rootNode : item);
|
||||||
|
|
||||||
return (int) [[n subpaths] count];
|
return (int) [[n subpaths] count];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
|
||||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
|
PathNode *n = (item == nil ? rootNode : item);
|
||||||
{
|
|
||||||
PathNode *n = (item == nil ? rootNode : item);
|
|
||||||
|
|
||||||
return ([n isLeaf] == NO);
|
return ![n isLeaf];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
|
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
|
||||||
{
|
PathNode *n = (item == nil ? rootNode : item);
|
||||||
PathNode *n = (item == nil ? rootNode : item);
|
|
||||||
|
|
||||||
return [[n subpaths] objectAtIndex:index];
|
return [n subpaths][(NSUInteger) index];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
|
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
||||||
{
|
PathNode *n = (item == nil ? rootNode : item);
|
||||||
PathNode *n = (item == nil ? rootNode : item);
|
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Drag it drop it
|
- (id <NSPasteboardWriting>)outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item {
|
||||||
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard {
|
NSPasteboardItem *paste = [[NSPasteboardItem alloc] init];
|
||||||
//Get selected paths
|
[paste setData:[[item URL] dataRepresentation] forType:NSPasteboardTypeFileURL];
|
||||||
NSMutableArray *urls = [NSMutableArray arrayWithCapacity:[items count]];
|
return paste;
|
||||||
NSMutableArray *paths = [NSMutableArray arrayWithCapacity:[items count]];
|
|
||||||
|
|
||||||
for (id p in items) {
|
|
||||||
[urls addObject:[p URL]];
|
|
||||||
[paths addObject:[[p URL] path]];
|
|
||||||
}
|
|
||||||
DLog(@"Paths: %@", paths);
|
|
||||||
[pboard declareTypes:[NSArray arrayWithObjects:CogUrlsPboardType,nil] owner:nil]; //add it to pboard
|
|
||||||
[pboard setData:[NSArchiver archivedDataWithRootObject:urls] forType:CogUrlsPboardType];
|
|
||||||
[pboard addTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
|
|
||||||
[pboard setPropertyList:paths forType:NSFilenamesPboardType];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reloadPathNode:(PathNode *)item
|
- (void)reloadPathNode:(PathNode *)item {
|
||||||
{
|
if (item == rootNode) {
|
||||||
if (item == rootNode)
|
[self.outlineView reloadData];
|
||||||
{
|
} else {
|
||||||
[outlineView reloadData];
|
[self.outlineView reloadItem:item reloadChildren:YES];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
[outlineView reloadItem:item reloadChildren:YES];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
extern NSString *CogPlaylistItemType;
|
extern NSString *CogDNDIndexType;
|
||||||
extern NSString *CogUrlsPboardType;
|
extern NSString *CogUrlsPboardType;
|
||||||
extern NSString *iTunesDropType;
|
extern NSString *iTunesDropType;
|
||||||
|
|
||||||
|
@ -12,13 +12,17 @@ extern NSString *iTunesDropType;
|
||||||
// table view drag and drop support
|
// table view drag and drop support
|
||||||
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView
|
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView
|
||||||
pasteboardWriterForRow:(NSInteger)row;
|
pasteboardWriterForRow:(NSInteger)row;
|
||||||
|
- (void)tableView:(NSTableView *)tableView
|
||||||
|
draggingSession:(NSDraggingSession *)session
|
||||||
|
willBeginAtPoint:(NSPoint)screenPoint
|
||||||
|
forRowIndexes:(NSIndexSet *)rowIndexes;
|
||||||
- (NSDragOperation)tableView:(NSTableView *)tableView
|
- (NSDragOperation)tableView:(NSTableView *)tableView
|
||||||
validateDrop:(id <NSDraggingInfo>)info
|
validateDrop:(id <NSDraggingInfo>)info
|
||||||
proposedRow:(int)row
|
proposedRow:(NSInteger)row
|
||||||
proposedDropOperation:(NSTableViewDropOperation)dropOperation;
|
proposedDropOperation:(NSTableViewDropOperation)dropOperation;
|
||||||
- (BOOL)tableView:(NSTableView *)tableView
|
- (BOOL)tableView:(NSTableView *)tableView
|
||||||
acceptDrop:(id <NSDraggingInfo>)info
|
acceptDrop:(id <NSDraggingInfo>)info
|
||||||
row:(int)row
|
row:(NSInteger)row
|
||||||
dropOperation:(NSTableViewDropOperation)dropOperation;
|
dropOperation:(NSTableViewDropOperation)dropOperation;
|
||||||
|
|
||||||
// utility methods
|
// utility methods
|
||||||
|
|
|
@ -3,45 +3,43 @@
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
NSString *CogDNDIndexType = @"org.cogx.cog.dnd-index";
|
||||||
|
NSString *CogUrlsPboardType = @"org.cogx.cog.url";
|
||||||
|
NSString *iTunesDropType = @"com.apple.tv.metadata";
|
||||||
|
|
||||||
@implementation DNDArrayController
|
@implementation DNDArrayController
|
||||||
|
|
||||||
NSString *CogPlaylistItemType = @"org.cogx.cog.playlist-item";
|
- (void)awakeFromNib {
|
||||||
NSString *CogUrlsPboardType = @"COG_URLS_TYPE";
|
[super awakeFromNib];
|
||||||
|
|
||||||
// @"CorePasteboardFlavorType 0x6974756E" is the "itun" type representing an iTunes plist
|
|
||||||
NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
|
|
||||||
|
|
||||||
- (void)awakeFromNib
|
|
||||||
{
|
|
||||||
// register for drag and drop
|
// register for drag and drop
|
||||||
[self.tableView registerForDraggedTypes:@[CogPlaylistItemType, CogUrlsPboardType,
|
[self.tableView registerForDraggedTypes:@[CogDNDIndexType,
|
||||||
NSFilenamesPboardType, iTunesDropType]];
|
CogUrlsPboardType,
|
||||||
|
NSPasteboardTypeFileURL,
|
||||||
|
iTunesDropType]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView
|
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView
|
||||||
pasteboardWriterForRow:(NSInteger)row
|
pasteboardWriterForRow:(NSInteger)row {
|
||||||
{
|
|
||||||
NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
|
NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
|
||||||
[item setString:[@(row) stringValue] forType:CogPlaylistItemType];
|
[item setString:[@(row) stringValue] forType:CogDNDIndexType];
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)tableView:(NSTableView *)tableView
|
- (void)tableView:(NSTableView *)tableView
|
||||||
draggingSession:(NSDraggingSession *)session
|
draggingSession:(NSDraggingSession *)session
|
||||||
willBeginAtPoint:(NSPoint)screenPoint
|
willBeginAtPoint:(NSPoint)screenPoint
|
||||||
forRowIndexes:(NSIndexSet *)rowIndexes
|
forRowIndexes:(NSIndexSet *)rowIndexes {
|
||||||
{
|
|
||||||
DLog(@"Drag session started with indexes: %@", rowIndexes);
|
DLog(@"Drag session started with indexes: %@", rowIndexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSDragOperation)tableView:(NSTableView*)tableView
|
- (NSDragOperation)tableView:(NSTableView *)tableView
|
||||||
validateDrop:(id <NSDraggingInfo>)info
|
validateDrop:(id <NSDraggingInfo>)info
|
||||||
proposedRow:(int)row
|
proposedRow:(NSInteger)row
|
||||||
proposedDropOperation:(NSTableViewDropOperation)dropOperation
|
proposedDropOperation:(NSTableViewDropOperation)dropOperation {
|
||||||
{
|
|
||||||
NSDragOperation dragOp = NSDragOperationCopy;
|
NSDragOperation dragOp = NSDragOperationCopy;
|
||||||
|
|
||||||
if ([info draggingSource] == tableView)
|
if ([info draggingSource] == tableView)
|
||||||
|
@ -56,29 +54,28 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)tableView:(NSTableView*)tableView
|
- (BOOL)tableView:(NSTableView *)tableView
|
||||||
acceptDrop:(id <NSDraggingInfo>)info
|
acceptDrop:(id <NSDraggingInfo>)info
|
||||||
row:(int)row
|
row:(NSInteger)row
|
||||||
dropOperation:(NSTableViewDropOperation)dropOperation
|
dropOperation:(NSTableViewDropOperation)dropOperation {
|
||||||
{
|
|
||||||
if (row < 0) {
|
if (row < 0) {
|
||||||
row = 0;
|
row = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray<NSPasteboardItem *> *items = info.draggingPasteboard.pasteboardItems;
|
NSArray<NSPasteboardItem *> *items = info.draggingPasteboard.pasteboardItems;
|
||||||
// if drag source is self, it's a move
|
// if drag source is self, it's a move
|
||||||
if ([info draggingSource] == tableView || items == nil) {
|
if ([info draggingSource] == tableView || items == nil) {
|
||||||
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
|
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
|
||||||
for (NSPasteboardItem *item in items) {
|
for (NSPasteboardItem *item in items) {
|
||||||
[indexSet addIndex:[[item stringForType:CogPlaylistItemType] intValue]];
|
[indexSet addIndex:(NSUInteger) [[item stringForType:CogDNDIndexType] intValue]];
|
||||||
}
|
}
|
||||||
if ([indexSet count] > 0) {
|
if ([indexSet count] > 0) {
|
||||||
DLog(@"INDEX SET ON DROP: %@", indexSet);
|
DLog(@"INDEX SET ON DROP: %@", indexSet);
|
||||||
NSArray *selected = [[self arrangedObjects] objectsAtIndexes:indexSet];
|
NSArray *selected = [[self arrangedObjects] objectsAtIndexes:indexSet];
|
||||||
[self moveObjectsInArrangedObjectsFromIndexes:indexSet toIndex:row];
|
[self moveObjectsInArrangedObjectsFromIndexes:indexSet toIndex:(unsigned int) row];
|
||||||
|
|
||||||
[self setSelectedObjects:selected];
|
[self setSelectedObjects:selected];
|
||||||
|
|
||||||
DLog(@"ACCEPTING DROP!");
|
DLog(@"ACCEPTING DROP!");
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
@ -88,26 +85,25 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
-(void) moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet
|
- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet
|
||||||
toIndex:(unsigned int)insertIndex
|
toIndex:(unsigned int)insertIndex {
|
||||||
{
|
NSArray *objects = [self arrangedObjects];
|
||||||
NSArray *objects = [self arrangedObjects];
|
NSUInteger index = [indexSet lastIndex];
|
||||||
NSUInteger index = [indexSet lastIndex];
|
|
||||||
|
|
||||||
int aboveInsertIndexCount = 0;
|
NSUInteger aboveInsertIndexCount = 0;
|
||||||
id object;
|
id object;
|
||||||
int removeIndex;
|
NSUInteger removeIndex;
|
||||||
|
|
||||||
while (NSNotFound != index) {
|
while (NSNotFound != index) {
|
||||||
if (index >= insertIndex) {
|
if (index >= insertIndex) {
|
||||||
removeIndex = (int)(index + aboveInsertIndexCount);
|
removeIndex = index + aboveInsertIndexCount;
|
||||||
aboveInsertIndexCount += 1;
|
aboveInsertIndexCount += 1;
|
||||||
} else {
|
} else {
|
||||||
removeIndex = (int)index;
|
removeIndex = index;
|
||||||
insertIndex -= 1;
|
insertIndex -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
object = [objects objectAtIndex:removeIndex];
|
object = objects[removeIndex];
|
||||||
|
|
||||||
[self removeObjectAtArrangedObjectIndex:removeIndex];
|
[self removeObjectAtArrangedObjectIndex:removeIndex];
|
||||||
[self insertObject:object atArrangedObjectIndex:insertIndex];
|
[self insertObject:object atArrangedObjectIndex:insertIndex];
|
||||||
|
|
|
@ -15,55 +15,48 @@
|
||||||
@class SpotlightWindowController;
|
@class SpotlightWindowController;
|
||||||
@class PlaybackController;
|
@class PlaybackController;
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSInteger, RepeatMode) {
|
||||||
RepeatNone = 0,
|
RepeatModeNoRepeat = 0,
|
||||||
RepeatOne,
|
RepeatModeRepeatOne,
|
||||||
RepeatAlbum,
|
RepeatModeRepeatAlbum,
|
||||||
RepeatAll
|
RepeatModeRepeatAll
|
||||||
} RepeatMode;
|
};
|
||||||
|
|
||||||
static inline BOOL IsRepeatOneSet()
|
static inline BOOL IsRepeatOneSet() {
|
||||||
{
|
return [[NSUserDefaults standardUserDefaults] integerForKey:@"repeat"] == RepeatModeRepeatOne;
|
||||||
return [[NSUserDefaults standardUserDefaults] integerForKey:@"repeat"] == RepeatOne;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum { ShuffleOff = 0, ShuffleAlbums, ShuffleAll } ShuffleMode;
|
||||||
ShuffleOff = 0,
|
|
||||||
ShuffleAlbums,
|
|
||||||
ShuffleAll
|
|
||||||
} ShuffleMode;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSInteger, URLOrigin) {
|
||||||
URLOriginInternal = 0,
|
URLOriginInternal = 0,
|
||||||
URLOriginExternal,
|
URLOriginExternal
|
||||||
} URLOrigin;
|
};
|
||||||
|
|
||||||
|
@interface PlaylistController : DNDArrayController <NSTableViewDelegate> {
|
||||||
|
IBOutlet PlaylistLoader *playlistLoader;
|
||||||
|
IBOutlet SpotlightWindowController *spotlightWindowController;
|
||||||
|
IBOutlet PlaybackController *playbackController;
|
||||||
|
|
||||||
|
NSMutableArray *shuffleList;
|
||||||
|
NSMutableArray *queueList;
|
||||||
|
|
||||||
|
NSString *totalTime;
|
||||||
|
|
||||||
|
PlaylistEntry *currentEntry;
|
||||||
|
|
||||||
@interface PlaylistController : DNDArrayController {
|
|
||||||
IBOutlet PlaylistLoader *playlistLoader;
|
|
||||||
IBOutlet SpotlightWindowController *spotlightWindowController;
|
|
||||||
IBOutlet PlaybackController *playbackController;
|
|
||||||
|
|
||||||
NSMutableArray *shuffleList;
|
|
||||||
NSMutableArray *queueList;
|
|
||||||
|
|
||||||
NSString *totalTime;
|
|
||||||
|
|
||||||
PlaylistEntry *currentEntry;
|
|
||||||
|
|
||||||
NSUndoManager *undoManager;
|
NSUndoManager *undoManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property(nonatomic, retain) PlaylistEntry *currentEntry;
|
@property(nonatomic, retain) PlaylistEntry *currentEntry;
|
||||||
@property(retain) NSString *totalTime;
|
@property(retain) NSString *totalTime;
|
||||||
|
|
||||||
//Private Methods
|
// Private Methods
|
||||||
- (void)updateTotalTime;
|
- (void)updateTotalTime;
|
||||||
- (void)updatePlaylistIndexes;
|
- (void)updatePlaylistIndexes;
|
||||||
- (IBAction)stopAfterCurrent:(id)sender;
|
- (IBAction)stopAfterCurrent:(id)sender;
|
||||||
|
|
||||||
|
// PUBLIC METHODS
|
||||||
//PUBLIC METHODS
|
|
||||||
- (void)setShuffle:(ShuffleMode)s;
|
- (void)setShuffle:(ShuffleMode)s;
|
||||||
- (ShuffleMode)shuffle;
|
- (ShuffleMode)shuffle;
|
||||||
- (void)setRepeat:(RepeatMode)r;
|
- (void)setRepeat:(RepeatMode)r;
|
||||||
|
@ -95,7 +88,7 @@ typedef enum {
|
||||||
- (IBAction)searchByArtist:(id)sender;
|
- (IBAction)searchByArtist:(id)sender;
|
||||||
- (IBAction)searchByAlbum:(id)sender;
|
- (IBAction)searchByAlbum:(id)sender;
|
||||||
|
|
||||||
//FUN PLAYLIST MANAGEMENT STUFF!
|
// FUN PLAYLIST MANAGEMENT STUFF!
|
||||||
- (BOOL)next;
|
- (BOOL)next;
|
||||||
- (BOOL)prev;
|
- (BOOL)prev;
|
||||||
|
|
||||||
|
@ -107,12 +100,15 @@ typedef enum {
|
||||||
- (PlaylistEntry *)entryAtIndex:(int)i;
|
- (PlaylistEntry *)entryAtIndex:(int)i;
|
||||||
|
|
||||||
// Event inlets:
|
// Event inlets:
|
||||||
- (void)willInsertURLs:(NSArray*)urls origin:(URLOrigin)origin;
|
- (void)willInsertURLs:(NSArray *)urls origin:(URLOrigin)origin;
|
||||||
- (void)didInsertURLs:(NSArray*)urls origin:(URLOrigin)origin;
|
- (void)didInsertURLs:(NSArray *)urls origin:(URLOrigin)origin;
|
||||||
|
|
||||||
// queue methods
|
// queue methods
|
||||||
- (IBAction)toggleQueued:(id)sender;
|
- (IBAction)toggleQueued:(id)sender;
|
||||||
- (IBAction)emptyQueueList:(id)sender;
|
- (IBAction)emptyQueueList:(id)sender;
|
||||||
- (NSMutableArray *)queueList;
|
- (NSMutableArray *)queueList;
|
||||||
|
|
||||||
|
- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet
|
||||||
|
toIndex:(unsigned int)insertIndex;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,11 +13,11 @@
|
||||||
#import "PlaylistLoader.h"
|
#import "PlaylistLoader.h"
|
||||||
|
|
||||||
@interface PlaylistView : NSTableView {
|
@interface PlaylistView : NSTableView {
|
||||||
IBOutlet PlaybackController *playbackController;
|
IBOutlet PlaybackController *playbackController;
|
||||||
IBOutlet PlaylistController *playlistController;
|
IBOutlet PlaylistController *playlistController;
|
||||||
IBOutlet PlaylistLoader *playlistLoader;
|
IBOutlet PlaylistLoader *playlistLoader;
|
||||||
|
|
||||||
NSMenu *headerContextMenu;
|
NSMenu *headerContextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)toggleColumn:(id)sender;
|
- (IBAction)toggleColumn:(id)sender;
|
||||||
|
|
|
@ -7,13 +7,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "PlaylistView.h"
|
#import "PlaylistView.h"
|
||||||
#import "PlaybackController.h"
|
|
||||||
#import "PlaylistController.h"
|
|
||||||
|
|
||||||
#import "IndexFormatter.h"
|
|
||||||
#import "SecondsFormatter.h"
|
|
||||||
#import "BlankZeroFormatter.h"
|
#import "BlankZeroFormatter.h"
|
||||||
|
#import "IndexFormatter.h"
|
||||||
#import "PlaylistEntry.h"
|
#import "PlaylistEntry.h"
|
||||||
|
#import "SecondsFormatter.h"
|
||||||
|
|
||||||
#import "CogAudio/Status.h"
|
#import "CogAudio/Status.h"
|
||||||
|
|
||||||
|
@ -21,377 +19,353 @@
|
||||||
|
|
||||||
@implementation PlaylistView
|
@implementation PlaylistView
|
||||||
|
|
||||||
- (void)awakeFromNib
|
- (void)awakeFromNib {
|
||||||
{
|
|
||||||
[[self menu] setAutoenablesItems:NO];
|
[[self menu] setAutoenablesItems:NO];
|
||||||
|
|
||||||
// Configure bindings to scale font size and row height
|
// Configure bindings to scale font size and row height
|
||||||
NSControlSize s = NSControlSizeSmall;
|
NSControlSize s = NSControlSizeSmall;
|
||||||
NSFont *f = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:s]];
|
NSFont *f = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:s]];
|
||||||
// NSFont *bf = [[NSFontManager sharedFontManager] convertFont:f toHaveTrait:NSBoldFontMask];
|
// NSFont *bf = [[NSFontManager sharedFontManager] convertFont:f toHaveTrait:NSBoldFontMask];
|
||||||
|
|
||||||
for (NSTableColumn *col in [self tableColumns]) {
|
for (NSTableColumn *col in [self tableColumns]) {
|
||||||
[[col dataCell] setControlSize:s];
|
[[col dataCell] setControlSize:s];
|
||||||
[[col dataCell] setFont:f];
|
[[col dataCell] setFont:f];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set up formatters
|
// Set up formatters
|
||||||
NSFormatter *secondsFormatter = [[SecondsFormatter alloc] init];
|
NSFormatter *secondsFormatter = [[SecondsFormatter alloc] init];
|
||||||
[[[self tableColumnWithIdentifier:@"length"] dataCell] setFormatter:secondsFormatter];
|
[[[self tableColumnWithIdentifier:@"length"] dataCell] setFormatter:secondsFormatter];
|
||||||
|
|
||||||
NSFormatter *indexFormatter = [[IndexFormatter alloc] init];
|
NSFormatter *indexFormatter = [[IndexFormatter alloc] init];
|
||||||
[[[self tableColumnWithIdentifier:@"index"] dataCell] setFormatter:indexFormatter];
|
[[[self tableColumnWithIdentifier:@"index"] dataCell] setFormatter:indexFormatter];
|
||||||
|
|
||||||
NSFormatter *blankZeroFormatter = [[BlankZeroFormatter alloc] init];
|
NSFormatter *blankZeroFormatter = [[BlankZeroFormatter alloc] init];
|
||||||
[[[self tableColumnWithIdentifier:@"track"] dataCell] setFormatter:blankZeroFormatter];
|
[[[self tableColumnWithIdentifier:@"track"] dataCell] setFormatter:blankZeroFormatter];
|
||||||
[[[self tableColumnWithIdentifier:@"year"] dataCell] setFormatter:blankZeroFormatter];
|
[[[self tableColumnWithIdentifier:@"year"] dataCell] setFormatter:blankZeroFormatter];
|
||||||
//end setting up formatters
|
// end setting up formatters
|
||||||
|
|
||||||
[self setVerticalMotionCanBeginDrag:YES];
|
[self setVerticalMotionCanBeginDrag:YES];
|
||||||
|
|
||||||
//Set up header context menu
|
// Set up header context menu
|
||||||
headerContextMenu = [[NSMenu alloc] initWithTitle:@"Playlist Header Context Menu"];
|
headerContextMenu = [[NSMenu alloc] initWithTitle:@"Playlist Header Context Menu"];
|
||||||
|
|
||||||
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"identifier" ascending:YES];
|
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"identifier"
|
||||||
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
|
ascending:YES];
|
||||||
|
NSArray *sortDescriptors = @[sortDescriptor];
|
||||||
|
|
||||||
int visibleTableColumns = 0;
|
int visibleTableColumns = 0;
|
||||||
int menuIndex = 0;
|
int menuIndex = 0;
|
||||||
for (NSTableColumn *col in [[self tableColumns] sortedArrayUsingDescriptors: sortDescriptors])
|
for (NSTableColumn *col in [[self tableColumns] sortedArrayUsingDescriptors:sortDescriptors]) {
|
||||||
{
|
|
||||||
NSString *title;
|
NSString *title;
|
||||||
if ([[col identifier] isEqualToString:@"status"])
|
if ([[col identifier] isEqualToString:@"status"]) {
|
||||||
{
|
|
||||||
title = @"Status";
|
title = @"Status";
|
||||||
}
|
} else if ([[col identifier] isEqualToString:@"index"]) {
|
||||||
else if ([[col identifier] isEqualToString:@"index"])
|
|
||||||
{
|
|
||||||
title = @"Index";
|
title = @"Index";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
title = [[col headerCell] title];
|
title = [[col headerCell] title];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMenuItem *contextMenuItem = [headerContextMenu insertItemWithTitle:title action:@selector(toggleColumn:) keyEquivalent:@"" atIndex:menuIndex];
|
NSMenuItem *contextMenuItem =
|
||||||
|
[headerContextMenu insertItemWithTitle:title
|
||||||
|
action:@selector(toggleColumn:)
|
||||||
|
keyEquivalent:@""
|
||||||
|
atIndex:menuIndex];
|
||||||
|
|
||||||
[contextMenuItem setTarget:self];
|
[contextMenuItem setTarget:self];
|
||||||
[contextMenuItem setRepresentedObject:col];
|
[contextMenuItem setRepresentedObject:col];
|
||||||
[contextMenuItem setState:([col isHidden] ? NSOffState : NSOnState)];
|
[contextMenuItem setState:([col isHidden] ? NSControlStateValueOff : NSControlStateValueOn)];
|
||||||
|
|
||||||
visibleTableColumns += ![col isHidden];
|
visibleTableColumns += ![col isHidden];
|
||||||
menuIndex++;
|
menuIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visibleTableColumns == 0) {
|
if (visibleTableColumns == 0) {
|
||||||
for (NSTableColumn *col in [self tableColumns]) {
|
for (NSTableColumn *col in [self tableColumns]) {
|
||||||
[col setHidden:NO];
|
[col setHidden:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[self headerView] setMenu:headerContextMenu];
|
[[self headerView] setMenu:headerContextMenu];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleColumn:(id)sender {
|
||||||
- (IBAction)toggleColumn:(id)sender
|
|
||||||
{
|
|
||||||
id tc = [sender representedObject];
|
id tc = [sender representedObject];
|
||||||
|
|
||||||
if ([sender state] == NSOffState)
|
if ([sender state] == NSControlStateValueOff) {
|
||||||
{
|
[sender setState:NSControlStateValueOn];
|
||||||
[sender setState:NSOnState];
|
|
||||||
|
[tc setHidden:NO];
|
||||||
[tc setHidden: NO];
|
} else {
|
||||||
}
|
[sender setState:NSControlStateValueOff];
|
||||||
else
|
|
||||||
{
|
[tc setHidden:YES];
|
||||||
[sender setState:NSOffState];
|
|
||||||
|
|
||||||
[tc setHidden: YES];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)acceptsFirstResponder
|
- (BOOL)acceptsFirstResponder {
|
||||||
{
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)resignFirstResponder
|
- (BOOL)resignFirstResponder {
|
||||||
{
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)acceptsFirstMouse:(NSEvent *)mouseDownEvent
|
- (BOOL)acceptsFirstMouse:(NSEvent *)mouseDownEvent {
|
||||||
{
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(NSEvent *)e
|
- (void)mouseDown:(NSEvent *)e {
|
||||||
{
|
|
||||||
[super mouseDown:e];
|
[super mouseDown:e];
|
||||||
|
|
||||||
if ([e type] == NSEventTypeLeftMouseDown && [e clickCount] == 2 && [[self selectedRowIndexes] count] == 1)
|
if ([e type] == NSEventTypeLeftMouseDown && [e clickCount] == 2 &&
|
||||||
{
|
[[self selectedRowIndexes] count] == 1) {
|
||||||
[playbackController play:self];
|
[playbackController play:self];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// enables right-click selection for "Show in Finder" contextual menu
|
// enables right-click selection for "Show in Finder" contextual menu
|
||||||
-(NSMenu*)menuForEvent:(NSEvent*)event
|
- (NSMenu *)menuForEvent:(NSEvent *)event {
|
||||||
{
|
// Find which row is under the cursor
|
||||||
//Find which row is under the cursor
|
|
||||||
[[self window] makeFirstResponder:self];
|
[[self window] makeFirstResponder:self];
|
||||||
NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
|
NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
|
||||||
NSInteger iRow = [self rowAtPoint:menuPoint];
|
NSInteger iRow = [self rowAtPoint:menuPoint];
|
||||||
NSMenu* tableViewMenu = [self menu];
|
NSMenu *tableViewMenu = [self menu];
|
||||||
|
|
||||||
/* Update the table selection before showing menu
|
/* Update the table selection before showing menu
|
||||||
Preserves the selection if the row under the mouse is selected (to allow for
|
Preserves the selection if the row under the mouse is selected (to allow for
|
||||||
multiple items to be selected), otherwise selects the row under the mouse */
|
multiple items to be selected), otherwise selects the row under the mouse */
|
||||||
BOOL currentRowIsSelected = [[self selectedRowIndexes] containsIndex:iRow];
|
BOOL currentRowIsSelected = [[self selectedRowIndexes] containsIndex:(NSUInteger) iRow];
|
||||||
if (!currentRowIsSelected) {
|
if (!currentRowIsSelected) {
|
||||||
if (iRow == -1)
|
if (iRow == -1) {
|
||||||
{
|
|
||||||
[self deselectAll:self];
|
[self deselectAll:self];
|
||||||
}
|
} else {
|
||||||
else
|
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:(NSUInteger) iRow] byExtendingSelection:NO];
|
||||||
{
|
|
||||||
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:iRow] byExtendingSelection:NO];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([self numberOfSelectedRows] <=0)
|
if ([self numberOfSelectedRows] <= 0) {
|
||||||
{
|
// No rows are selected, so the table should be displayed with all items disabled
|
||||||
//No rows are selected, so the table should be displayed with all items disabled
|
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<[tableViewMenu numberOfItems];i++) {
|
for (i = 0; i < [tableViewMenu numberOfItems]; i++) {
|
||||||
[[tableViewMenu itemAtIndex:i] setEnabled:NO];
|
[[tableViewMenu itemAtIndex:i] setEnabled:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tableViewMenu;
|
return tableViewMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)keyDown:(NSEvent *)e
|
- (void)keyDown:(NSEvent *)e {
|
||||||
{
|
unsigned int modifiers =
|
||||||
unsigned int modifiers = [e modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagShift | NSEventModifierFlagControl | NSEventModifierFlagOption);
|
[e modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagShift |
|
||||||
NSString *characters = [e characters];
|
NSEventModifierFlagControl | NSEventModifierFlagOption);
|
||||||
unichar c;
|
NSString *characters = [e characters];
|
||||||
|
unichar c;
|
||||||
if ([characters length] != 1)
|
|
||||||
{
|
if ([characters length] != 1) {
|
||||||
[super keyDown:e];
|
[super keyDown:e];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = [characters characterAtIndex:0];
|
c = [characters characterAtIndex:0];
|
||||||
if (modifiers == 0 && (c == NSDeleteCharacter || c == NSBackspaceCharacter || c == NSDeleteFunctionKey))
|
if (modifiers == 0 &&
|
||||||
{
|
(c == NSDeleteCharacter || c == NSBackspaceCharacter || c == NSDeleteFunctionKey)) {
|
||||||
[playlistController remove:self];
|
[playlistController remove:self];
|
||||||
}
|
} else if (modifiers == 0 && c == ' ') {
|
||||||
else if (modifiers == 0 && c == ' ')
|
|
||||||
{
|
|
||||||
[playbackController playPauseResume:self];
|
[playbackController playPauseResume:self];
|
||||||
}
|
} else if (modifiers == 0 && (c == NSEnterCharacter || c == NSCarriageReturnCharacter)) {
|
||||||
else if (modifiers == 0 && (c == NSEnterCharacter || c == NSCarriageReturnCharacter))
|
|
||||||
{
|
|
||||||
[playbackController play:self];
|
[playbackController play:self];
|
||||||
}
|
} else if (modifiers == 0 && c == NSLeftArrowFunctionKey) {
|
||||||
else if (modifiers == 0 && c == NSLeftArrowFunctionKey)
|
|
||||||
{
|
|
||||||
[playbackController eventSeekBackward:self];
|
[playbackController eventSeekBackward:self];
|
||||||
}
|
} else if (modifiers == 0 && c == NSRightArrowFunctionKey) {
|
||||||
else if (modifiers == 0 && c == NSRightArrowFunctionKey)
|
|
||||||
{
|
|
||||||
[playbackController eventSeekForward:self];
|
[playbackController eventSeekForward:self];
|
||||||
}
|
}
|
||||||
// Escape
|
// Escape
|
||||||
else if (modifiers == 0 && c == 0x1b)
|
else if (modifiers == 0 && c == 0x1b) {
|
||||||
{
|
|
||||||
[playlistController clearFilterPredicate:self];
|
[playlistController clearFilterPredicate:self];
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
[super keyDown:e];
|
[super keyDown:e];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)scrollToCurrentEntry:(id)sender
|
- (IBAction)scrollToCurrentEntry:(id)sender {
|
||||||
{
|
|
||||||
[self scrollRowToVisible:[[playlistController currentEntry] index]];
|
[self scrollRowToVisible:[[playlistController currentEntry] index]];
|
||||||
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:[[playlistController currentEntry] index]] byExtendingSelection:NO];
|
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:(NSUInteger) [[playlistController currentEntry] index]]
|
||||||
|
byExtendingSelection:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)undo:(id)sender
|
- (IBAction)undo:(id)sender {
|
||||||
{
|
|
||||||
[[playlistController undoManager] undo];
|
[[playlistController undoManager] undo];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)redo:(id)sender
|
- (IBAction)redo:(id)sender {
|
||||||
{
|
|
||||||
[[playlistController undoManager] redo];
|
[[playlistController undoManager] redo];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)copy:(id)sender
|
- (IBAction)copy:(id)sender {
|
||||||
{
|
|
||||||
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
||||||
|
|
||||||
[pboard clearContents];
|
[pboard clearContents];
|
||||||
|
|
||||||
NSMutableArray *selectedURLs = [[NSMutableArray alloc] init];
|
NSArray *entries =
|
||||||
|
[[playlistController content] objectsAtIndexes:[playlistController selectionIndexes]];
|
||||||
for (PlaylistEntry *pe in [[playlistController content] objectsAtIndexes:[playlistController selectionIndexes]])
|
NSUInteger capacity = [entries count];
|
||||||
{
|
NSMutableArray *selectedURLs = [NSMutableArray arrayWithCapacity:capacity];
|
||||||
|
|
||||||
|
for (PlaylistEntry *pe in entries) {
|
||||||
[selectedURLs addObject:[pe URL]];
|
[selectedURLs addObject:[pe URL]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[pboard setData:[NSArchiver archivedDataWithRootObject:selectedURLs] forType:CogUrlsPboardType];
|
NSError *error;
|
||||||
|
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:selectedURLs
|
||||||
NSMutableDictionary * tracks = [[NSMutableDictionary alloc] init];
|
requiringSecureCoding:YES
|
||||||
|
error:&error];
|
||||||
|
if (!data) {
|
||||||
|
DLog(@"Error: %@", error);
|
||||||
|
}
|
||||||
|
[pboard setData:data forType:CogUrlsPboardType];
|
||||||
|
|
||||||
|
NSMutableDictionary *tracks = [NSMutableDictionary dictionaryWithCapacity:capacity];
|
||||||
|
|
||||||
unsigned long i = 0;
|
unsigned long i = 0;
|
||||||
for (NSURL *url in selectedURLs)
|
for (NSURL *url in selectedURLs) {
|
||||||
{
|
tracks[[NSString stringWithFormat:@"%lu", i++]] = @{@"Location": [url absoluteString]};
|
||||||
NSMutableDictionary * track = [NSMutableDictionary dictionaryWithObjectsAndKeys:[url absoluteString], @"Location", nil];
|
|
||||||
[tracks setObject:track forKey:[NSString stringWithFormat:@"%lu", i]];
|
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableDictionary * itunesPlist = [NSMutableDictionary dictionaryWithObjectsAndKeys:tracks, @"Tracks", nil];
|
NSDictionary *itunesPlist = @{@"Tracks": tracks};
|
||||||
|
|
||||||
[pboard setPropertyList:itunesPlist forType:iTunesDropType];
|
[pboard setPropertyList:itunesPlist forType:iTunesDropType];
|
||||||
|
|
||||||
NSMutableArray *filePaths = [[NSMutableArray alloc] init];
|
NSMutableArray *filePaths = [NSMutableArray array];
|
||||||
|
|
||||||
for (NSURL *url in selectedURLs)
|
for (NSURL *url in selectedURLs) {
|
||||||
{
|
if ([url isFileURL]) {
|
||||||
if ([url isFileURL])
|
[filePaths addObject:url];
|
||||||
[filePaths addObject:[url path]];
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([filePaths count]) {
|
||||||
|
[pboard writeObjects:filePaths];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([filePaths count])
|
|
||||||
[pboard setPropertyList:filePaths forType:NSFilenamesPboardType];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)cut:(id)sender
|
- (IBAction)cut:(id)sender {
|
||||||
{
|
|
||||||
[self copy:sender];
|
[self copy:sender];
|
||||||
|
|
||||||
[playlistController removeObjectsAtArrangedObjectIndexes:[playlistController selectionIndexes]];
|
[playlistController removeObjectsAtArrangedObjectIndexes:[playlistController selectionIndexes]];
|
||||||
|
|
||||||
if ([playlistController shuffle] != ShuffleOff)
|
if ([playlistController shuffle] != ShuffleOff) [playlistController resetShuffleList];
|
||||||
[playlistController resetShuffleList];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)paste:(id)sender
|
- (IBAction)paste:(id)sender {
|
||||||
{
|
|
||||||
// Determine the type of object that was dropped
|
// Determine the type of object that was dropped
|
||||||
NSArray *supportedTypes = [NSArray arrayWithObjects:CogUrlsPboardType, NSFilenamesPboardType, iTunesDropType, nil];
|
NSArray *supportedTypes = @[CogUrlsPboardType, NSPasteboardTypeFileURL, iTunesDropType];
|
||||||
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
||||||
NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
|
NSPasteboardType bestType = [pboard availableTypeFromArray:supportedTypes];
|
||||||
|
DLog(@"All types:");
|
||||||
NSMutableArray *acceptedURLs = [[NSMutableArray alloc] init];
|
for (NSPasteboardType type in [pboard types]) {
|
||||||
|
DLog(@" Type: %@", type);
|
||||||
|
}
|
||||||
|
DLog(@"Supported types:");
|
||||||
|
for (NSPasteboardType type in supportedTypes) {
|
||||||
|
DLog(@" Type: %@", type);
|
||||||
|
}
|
||||||
|
DLog(@"Best type: %@", bestType);
|
||||||
|
|
||||||
|
NSMutableArray *acceptedURLs = [NSMutableArray array];
|
||||||
|
|
||||||
// Get files from an file drawer drop
|
// Get files from an file drawer drop
|
||||||
if ([bestType isEqualToString:CogUrlsPboardType]) {
|
if ([bestType isEqualToString:CogUrlsPboardType]) {
|
||||||
NSArray *urls = [NSUnarchiver unarchiveObjectWithData:[pboard dataForType:CogUrlsPboardType]];
|
NSError *error;
|
||||||
DLog(@"URLS: %@", urls);
|
NSData *data = [pboard dataForType:CogUrlsPboardType];
|
||||||
|
NSArray *urls;
|
||||||
|
if (@available(macOS 11.0, *)) {
|
||||||
|
urls = [NSKeyedUnarchiver unarchivedArrayOfObjectsOfClass:[NSURL class]
|
||||||
|
fromData:data
|
||||||
|
error:&error];
|
||||||
|
} else {
|
||||||
|
NSSet *allowed = [NSSet setWithArray:@[[NSArray class], [NSURL class]]];
|
||||||
|
urls = [NSKeyedUnarchiver unarchivedObjectOfClasses:allowed fromData:data error:&error];
|
||||||
|
}
|
||||||
|
if (!urls) {
|
||||||
|
DLog(@"%@", error);
|
||||||
|
} else {
|
||||||
|
DLog(@"URLS: %@", urls);
|
||||||
|
}
|
||||||
//[playlistLoader insertURLs: urls atIndex:row sort:YES];
|
//[playlistLoader insertURLs: urls atIndex:row sort:YES];
|
||||||
[acceptedURLs addObjectsFromArray:urls];
|
[acceptedURLs addObjectsFromArray:urls];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get files from a normal file drop (such as from Finder)
|
// Get files from a normal file drop (such as from Finder)
|
||||||
if ([bestType isEqualToString:NSFilenamesPboardType]) {
|
if ([bestType isEqualToString:NSPasteboardTypeFileURL]) {
|
||||||
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
for (NSString *file in [pboard propertyListForType:NSFilenamesPboardType])
|
for (NSString *file in [pboard propertyListForType:NSPasteboardTypeFileURL]) {
|
||||||
{
|
|
||||||
[urls addObject:[NSURL fileURLWithPath:file]];
|
[urls addObject:[NSURL fileURLWithPath:file]];
|
||||||
}
|
}
|
||||||
|
|
||||||
//[playlistLoader insertURLs:urls atIndex:row sort:YES];
|
//[playlistLoader insertURLs:urls atIndex:row sort:YES];
|
||||||
[acceptedURLs addObjectsFromArray:urls];
|
[acceptedURLs addObjectsFromArray:urls];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get files from an iTunes drop
|
// Get files from an iTunes drop
|
||||||
if ([bestType isEqualToString:iTunesDropType]) {
|
if ([bestType isEqualToString:iTunesDropType]) {
|
||||||
NSDictionary *iTunesDict = [pboard propertyListForType:iTunesDropType];
|
NSDictionary *iTunesDict = [pboard propertyListForType:iTunesDropType];
|
||||||
NSDictionary *tracks = [iTunesDict valueForKey:@"Tracks"];
|
NSDictionary *tracks = [iTunesDict valueForKey:@"Tracks"];
|
||||||
|
|
||||||
// Convert the iTunes URLs to URLs....MWAHAHAH!
|
// Convert the iTunes URLs to URLs....MWAHAHAH!
|
||||||
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
for (NSDictionary *trackInfo in [tracks allValues]) {
|
for (NSDictionary *trackInfo in [tracks allValues]) {
|
||||||
[urls addObject:[NSURL URLWithString:[trackInfo valueForKey:@"Location"]]];
|
[urls addObject:[NSURL URLWithString:[trackInfo valueForKey:@"Location"]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
//[playlistLoader insertURLs:urls atIndex:row sort:YES];
|
//[playlistLoader insertURLs:urls atIndex:row sort:YES];
|
||||||
[acceptedURLs addObjectsFromArray:urls];
|
[acceptedURLs addObjectsFromArray:urls];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([acceptedURLs count])
|
if ([acceptedURLs count]) {
|
||||||
{
|
|
||||||
NSUInteger row = [[playlistController content] count];
|
NSUInteger row = [[playlistController content] count];
|
||||||
|
|
||||||
[playlistController willInsertURLs:acceptedURLs origin:URLOriginInternal];
|
[playlistController willInsertURLs:acceptedURLs origin:URLOriginInternal];
|
||||||
|
|
||||||
NSArray* entries = [playlistLoader insertURLs:acceptedURLs atIndex:(int)row sort:NO];
|
NSArray *entries = [playlistLoader insertURLs:acceptedURLs atIndex:(int) row sort:NO];
|
||||||
[playlistLoader didInsertURLs:entries origin:URLOriginInternal];
|
[playlistLoader didInsertURLs:entries origin:URLOriginInternal];
|
||||||
|
|
||||||
if ([playlistController shuffle] != ShuffleOff)
|
if ([playlistController shuffle] != ShuffleOff) [playlistController resetShuffleList];
|
||||||
[playlistController resetShuffleList];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)delete:(id)sender
|
- (IBAction)delete:(id)sender {
|
||||||
{
|
|
||||||
[playlistController removeObjectsAtArrangedObjectIndexes:[playlistController selectionIndexes]];
|
[playlistController removeObjectsAtArrangedObjectIndexes:[playlistController selectionIndexes]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem {
|
||||||
-(BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
|
|
||||||
{
|
|
||||||
SEL action = [anItem action];
|
SEL action = [anItem action];
|
||||||
|
|
||||||
if (action == @selector(undo:))
|
if (action == @selector(undo:)) {
|
||||||
{
|
return [[playlistController undoManager] canUndo];
|
||||||
if ([[playlistController undoManager] canUndo])
|
|
||||||
return YES;
|
|
||||||
else
|
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
if (action == @selector(redo:))
|
if (action == @selector(redo:)) {
|
||||||
{
|
return [[playlistController undoManager] canRedo];
|
||||||
if ([[playlistController undoManager] canRedo])
|
|
||||||
return YES;
|
|
||||||
else
|
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
if (action == @selector(cut:) || action == @selector(copy:) || action == @selector(delete:))
|
if (action == @selector(cut:) || action == @selector(copy:) || action == @selector(delete:)) {
|
||||||
{
|
return [[playlistController selectionIndexes] count] != 0;
|
||||||
if ([[playlistController selectionIndexes] count] == 0)
|
|
||||||
return NO;
|
|
||||||
else
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
if (action == @selector(paste:))
|
if (action == @selector(paste:)) {
|
||||||
{
|
|
||||||
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
||||||
|
|
||||||
NSArray *supportedTypes = [NSArray arrayWithObjects:CogUrlsPboardType, NSFilenamesPboardType, iTunesDropType, nil];
|
NSArray *supportedTypes = @[CogUrlsPboardType, NSPasteboardTypeFileURL, iTunesDropType];
|
||||||
|
|
||||||
NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
|
NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
|
||||||
|
|
||||||
if (bestType != nil)
|
return bestType != nil;
|
||||||
return YES;
|
|
||||||
else
|
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == @selector(scrollToCurrentEntry:) && (([playbackController playbackStatus] == kCogStatusStopped) || ([playbackController playbackStatus] == kCogStatusStopping)))
|
if (action == @selector(scrollToCurrentEntry:) &&
|
||||||
|
(([playbackController playbackStatus] == kCogStatusStopped) ||
|
||||||
|
([playbackController playbackStatus] == kCogStatusStopping)))
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
return [super validateUserInterfaceItem:anItem];
|
return [super validateUserInterfaceItem:anItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,5 +379,4 @@
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface XmlContainer : NSObject {
|
@interface XmlContainer : NSObject
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename;
|
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename;
|
||||||
|
|
||||||
|
|
|
@ -8,101 +8,109 @@
|
||||||
|
|
||||||
#import "XmlContainer.h"
|
#import "XmlContainer.h"
|
||||||
|
|
||||||
#import "PlaylistEntry.h"
|
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
@implementation XmlContainer
|
@implementation XmlContainer
|
||||||
|
|
||||||
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename
|
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename {
|
||||||
{
|
NSRange protocolRange = [path rangeOfString:@"://"];
|
||||||
NSRange protocolRange = [path rangeOfString:@"://"];
|
if (protocolRange.location != NSNotFound) {
|
||||||
if (protocolRange.location != NSNotFound)
|
return [NSURL URLWithString:path];
|
||||||
{
|
}
|
||||||
return [NSURL URLWithString:path];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableString *unixPath = [path mutableCopy];
|
NSMutableString *unixPath = [path mutableCopy];
|
||||||
|
|
||||||
//Get the fragment
|
//Get the fragment
|
||||||
NSString *fragment = @"";
|
NSString *fragment = @"";
|
||||||
NSScanner *scanner = [NSScanner scannerWithString:unixPath];
|
NSScanner *scanner = [NSScanner scannerWithString:unixPath];
|
||||||
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"#1234567890"];
|
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"#1234567890"];
|
||||||
while (![scanner isAtEnd]) {
|
while (![scanner isAtEnd]) {
|
||||||
NSString *possibleFragment;
|
NSString *possibleFragment;
|
||||||
[scanner scanUpToString:@"#" intoString:nil];
|
[scanner scanUpToString:@"#" intoString:nil];
|
||||||
|
|
||||||
if ([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd])
|
if ([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd]) {
|
||||||
{
|
fragment = possibleFragment;
|
||||||
fragment = possibleFragment;
|
[unixPath deleteCharactersInRange:NSMakeRange([scanner scanLocation] - [possibleFragment length], [possibleFragment length])];
|
||||||
[unixPath deleteCharactersInRange:NSMakeRange([scanner scanLocation] - [possibleFragment length], [possibleFragment length])];
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
DLog(@"Fragment: %@", fragment);
|
||||||
DLog(@"Fragment: %@", fragment);
|
|
||||||
|
|
||||||
if (![unixPath hasPrefix:@"/"]) {
|
if (![unixPath hasPrefix:@"/"]) {
|
||||||
//Only relative paths would have windows backslashes.
|
//Only relative paths would have windows backslashes.
|
||||||
[unixPath replaceOccurrencesOfString:@"\\" withString:@"/" options:0 range:NSMakeRange(0, [unixPath length])];
|
[unixPath replaceOccurrencesOfString:@"\\" withString:@"/" options:0 range:NSMakeRange(0, [unixPath length])];
|
||||||
|
|
||||||
NSString *basePath = [[[baseFilename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"];
|
|
||||||
|
|
||||||
[unixPath insertString:basePath atIndex:0];
|
NSString *basePath = [[[baseFilename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"];
|
||||||
}
|
|
||||||
|
[unixPath insertString:basePath atIndex:0];
|
||||||
//Append the fragment
|
}
|
||||||
NSURL *url = [NSURL URLWithString:[[[NSURL fileURLWithPath:unixPath] absoluteString] stringByAppendingString: fragment]];
|
|
||||||
return url;
|
//Append the fragment
|
||||||
|
NSURL *url = [NSURL URLWithString:[[[NSURL fileURLWithPath:unixPath] absoluteString] stringByAppendingString:fragment]];
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary *)entriesForContainerURL:(NSURL *)url
|
+ (NSDictionary *)entriesForContainerURL:(NSURL *)url {
|
||||||
{
|
if (![url isFileURL])
|
||||||
if (![url isFileURL])
|
return nil;
|
||||||
return [NSDictionary dictionary];
|
|
||||||
|
|
||||||
NSError *nserr;
|
NSError *error;
|
||||||
|
|
||||||
NSString *error;
|
NSString *filename = [url path];
|
||||||
|
|
||||||
NSString *filename = [url path];
|
NSString *contents = [NSString stringWithContentsOfFile:filename
|
||||||
|
encoding:NSUTF8StringEncoding
|
||||||
NSString * contents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:&nserr];
|
error:&error];
|
||||||
|
if (!contents) {
|
||||||
NSData* plistData = [contents dataUsingEncoding:NSUTF8StringEncoding];
|
ALog(@"Error: %@", error);
|
||||||
|
|
||||||
NSPropertyListFormat format;
|
|
||||||
id plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
|
|
||||||
if(!plist){
|
|
||||||
ALog(@"Error: %@",error);
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSData *plistData = [contents dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
|
||||||
|
NSPropertyListFormat format;
|
||||||
|
id plist = [NSPropertyListSerialization propertyListWithData:plistData
|
||||||
|
options:NSPropertyListImmutable
|
||||||
|
format:&format
|
||||||
|
error:&error];
|
||||||
|
if (!plist) {
|
||||||
|
ALog(@"Error: %@", error);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL isArray = [plist isKindOfClass:[NSArray class]];
|
BOOL isArray = [plist isKindOfClass:[NSArray class]];
|
||||||
BOOL isDict = [plist isKindOfClass:[NSDictionary class]];
|
BOOL isDict = [plist isKindOfClass:[NSDictionary class]];
|
||||||
|
|
||||||
if (!isDict && !isArray) return nil;
|
|
||||||
|
|
||||||
NSArray * items = (isArray) ? (NSArray*)plist : [(NSDictionary *)plist objectForKey:@"items"];
|
|
||||||
|
|
||||||
NSDictionary *albumArt = (isArray) ? nil : [(NSDictionary *)plist objectForKey:@"albumArt"];
|
|
||||||
|
|
||||||
NSArray *queueList = (isArray) ? [NSArray array] : [(NSDictionary *)plist objectForKey:@"queue"];
|
if (!isDict && !isArray) return nil;
|
||||||
|
|
||||||
NSMutableArray *entries = [NSMutableArray array];
|
NSArray *items;
|
||||||
|
NSDictionary *albumArt;
|
||||||
for (NSDictionary *entry in items)
|
NSArray *queueList;
|
||||||
{
|
if (isArray) {
|
||||||
NSMutableDictionary * preparedEntry = [NSMutableDictionary dictionaryWithDictionary:entry];
|
items = (NSArray *) plist;
|
||||||
|
albumArt = nil;
|
||||||
[preparedEntry setObject:[self urlForPath:[preparedEntry objectForKey:@"URL"] relativeTo:filename] forKey:@"URL"];
|
queueList = [NSArray array];
|
||||||
|
} else {
|
||||||
if (albumArt && [preparedEntry objectForKey:@"albumArt"])
|
NSDictionary *dict = (NSDictionary *) plist;
|
||||||
[preparedEntry setObject:[albumArt objectForKey:[preparedEntry objectForKey:@"albumArt"]] forKey:@"albumArt"];
|
items = dict[@"items"];
|
||||||
|
albumArt = dict[@"albumArt"];
|
||||||
|
queueList = dict[@"queue"];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableArray *entries = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (NSDictionary *entry in items) {
|
||||||
|
NSMutableDictionary *preparedEntry = [NSMutableDictionary dictionaryWithDictionary:entry];
|
||||||
|
|
||||||
|
preparedEntry[@"URL"] = [self urlForPath:preparedEntry[@"URL"] relativeTo:filename];
|
||||||
|
|
||||||
|
if (albumArt && preparedEntry[@"albumArt"])
|
||||||
|
preparedEntry[@"albumArt"] = albumArt[preparedEntry[@"albumArt"]];
|
||||||
|
|
||||||
[entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]];
|
[entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [NSDictionary dictionaryWithObjectsAndKeys:entries, @"entries", queueList, @"queue", nil];
|
return @{@"entries": entries, @"queue": queueList};
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,9 +10,7 @@
|
||||||
|
|
||||||
#import "PlaylistController.h"
|
#import "PlaylistController.h"
|
||||||
|
|
||||||
@interface RepeatModeTransformer : NSValueTransformer {
|
@interface RepeatModeTransformer : NSValueTransformer
|
||||||
RepeatMode repeatMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithMode:(RepeatMode) r;
|
- (id)initWithMode:(RepeatMode) r;
|
||||||
|
|
||||||
|
|
|
@ -7,55 +7,47 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "RepeatTransformers.h"
|
#import "RepeatTransformers.h"
|
||||||
#import "PlaylistController.h"
|
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
@implementation RepeatModeTransformer
|
@implementation RepeatModeTransformer {
|
||||||
|
RepeatMode repeatMode;
|
||||||
|
}
|
||||||
|
|
||||||
+ (Class)transformedValueClass { return [NSNumber class]; }
|
+ (Class)transformedValueClass { return [NSNumber class]; }
|
||||||
+ (BOOL)allowsReverseTransformation { return YES; }
|
+ (BOOL)allowsReverseTransformation { return YES; }
|
||||||
|
|
||||||
- (id)initWithMode:(RepeatMode) r
|
- (id)initWithMode:(RepeatMode)r {
|
||||||
{
|
self = [super init];
|
||||||
self = [super init];
|
if (self) {
|
||||||
if (self)
|
repeatMode = r;
|
||||||
{
|
}
|
||||||
repeatMode = r;
|
|
||||||
}
|
return self;
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert from RepeatMode to BOOL
|
// Convert from RepeatMode to BOOL
|
||||||
- (id)transformedValue:(id)value {
|
- (id)transformedValue:(id)value {
|
||||||
DLog(@"Transforming value: %@", value);
|
DLog(@"Transforming value: %@", value);
|
||||||
|
|
||||||
if (value == nil) return nil;
|
|
||||||
|
|
||||||
RepeatMode mode = (RepeatMode) [value integerValue];
|
|
||||||
|
|
||||||
if (repeatMode == mode) {
|
|
||||||
return [NSNumber numberWithBool:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return [NSNumber numberWithBool:NO];
|
if (value == nil) return nil;
|
||||||
|
|
||||||
|
RepeatMode mode = (RepeatMode) [value integerValue];
|
||||||
|
|
||||||
|
return @(repeatMode == mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)reverseTransformedValue:(id)value {
|
- (id)reverseTransformedValue:(id)value {
|
||||||
if (value == nil) return nil;
|
if (value == nil) return nil;
|
||||||
|
|
||||||
BOOL enabled = [value boolValue];
|
BOOL enabled = [value boolValue];
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
return [NSNumber numberWithInt:repeatMode];
|
return @(repeatMode);
|
||||||
}
|
} else if (repeatMode == RepeatModeNoRepeat) {
|
||||||
else if(repeatMode == RepeatNone) {
|
return @(RepeatModeRepeatAll);
|
||||||
return [NSNumber numberWithInt:RepeatAll];
|
} else {
|
||||||
}
|
return @(RepeatModeNoRepeat);
|
||||||
else {
|
}
|
||||||
return [NSNumber numberWithInt:RepeatNone];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -67,26 +59,26 @@
|
||||||
|
|
||||||
// Convert from string to RepeatMode
|
// Convert from string to RepeatMode
|
||||||
- (id)transformedValue:(id)value {
|
- (id)transformedValue:(id)value {
|
||||||
DLog(@"Transforming value: %@", value);
|
DLog(@"Transforming value: %@", value);
|
||||||
|
|
||||||
if (value == nil) return nil;
|
if (value == nil) return nil;
|
||||||
|
|
||||||
RepeatMode mode = (RepeatMode) [value integerValue];
|
RepeatMode mode = (RepeatMode) [value integerValue];
|
||||||
|
|
||||||
if (mode == RepeatNone) {
|
|
||||||
return [NSImage imageNamed:@"repeatModeOffTemplate"];
|
|
||||||
}
|
|
||||||
else if (mode == RepeatOne) {
|
|
||||||
return [NSImage imageNamed:@"repeatModeOneTemplate"];
|
|
||||||
}
|
|
||||||
else if (mode == RepeatAlbum) {
|
|
||||||
return [NSImage imageNamed:@"repeatModeAlbumTemplate"];
|
|
||||||
}
|
|
||||||
else if (mode == RepeatAll) {
|
|
||||||
return [NSImage imageNamed:@"repeatModeAllTemplate"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil;
|
if (mode == RepeatModeNoRepeat) {
|
||||||
|
return [NSImage imageNamed:@"repeatModeOffTemplate"];
|
||||||
|
}
|
||||||
|
else if (mode == RepeatModeRepeatOne) {
|
||||||
|
return [NSImage imageNamed:@"repeatModeOneTemplate"];
|
||||||
|
}
|
||||||
|
else if (mode == RepeatModeRepeatAlbum) {
|
||||||
|
return [NSImage imageNamed:@"repeatModeAlbumTemplate"];
|
||||||
|
}
|
||||||
|
else if (mode == RepeatModeRepeatAll) {
|
||||||
|
return [NSImage imageNamed:@"repeatModeAllTemplate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in New Issue