Modernize several classes.

Use modern ObjC syntax.
Use new Pasteboard APIs.
Explicitly declare protocols.
CQTexperiment
Dzmitry Neviadomski 2021-01-31 02:14:08 +03:00
parent 730276a7e7
commit c1da9a66e1
12 changed files with 1210 additions and 1393 deletions

View File

@ -11,16 +11,12 @@
@class PathNode;
@class PathWatcher;
@interface FileTreeDataSource : NSObject {
PathNode *rootNode;
@interface FileTreeDataSource : NSObject <NSOutlineViewDataSource>
IBOutlet NSPathControl *pathControl;
IBOutlet PathWatcher *watcher;
IBOutlet NSOutlineView *outlineView;
}
@property(nonatomic, weak) IBOutlet NSOutlineView *outlineView;
@property(nonatomic, weak) IBOutlet NSPathControl *pathControl;
@property(nonatomic, weak) IBOutlet PathWatcher *watcher;
- (NSURL *)rootURL;
- (void)setRootURL:(NSURL *)rootURL;
- (void)changeURL:(NSURL *)rootURL;
- (void)reloadPathNode:(PathNode *)item;

View File

@ -8,89 +8,96 @@
#import "FileTreeDataSource.h"
#import "DNDArrayController.h"
#import "DirectoryNode.h"
#import "PathWatcher.h"
#import "Logging.h"
@implementation FileTreeDataSource
NSURL *defaultMusicDirectory() {
return [[NSFileManager defaultManager] URLForDirectory:NSMusicDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:NO
error:nil];
}
+ (void)initialize
{
NSMutableDictionary *userDefaultsValuesDict = [NSMutableDictionary dictionary];
@interface FileTreeDataSource()
[userDefaultsValuesDict setObject:[[NSURL fileURLWithPath:[@"~/Music" stringByExpandingTildeInPath]] absoluteString] forKey:@"fileTreeRootURL"];
@property NSURL *rootURL;
@end
@implementation FileTreeDataSource {
PathNode *rootNode;
}
+ (void)initialize {
NSString *path = [defaultMusicDirectory() absoluteString];
NSDictionary *userDefaultsValuesDict = @{@"fileTreeRootURL": path};
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
}
- (void)awakeFromNib
{
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.fileTreeRootURL" options:0 context:nil];
[self setRootURL: [NSURL URLWithString:[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]]];
[pathControl setTarget:self];
[pathControl setAction:@selector(pathControlAction:)];
- (void)awakeFromNib {
[self.pathControl setTarget:self];
[self.pathControl setAction:@selector(pathControlAction:)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
forKeyPath:@"values.fileTreeRootURL"
options:NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionInitial
context:nil];
}
- (void) observeValueForKeyPath:(NSString *)keyPath
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
DLog(@"File tree root URL: %@\n", [[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]);
context:(void *)context {
if ([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
[self setRootURL:[NSURL URLWithString:[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]]];
NSString *url =
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"];
DLog(@"File tree root URL: %@\n", url);
self.rootURL = [NSURL URLWithString:url];
}
}
- (void)changeURL:(NSURL *)url
{
if (url != nil)
{
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString] forKey:@"fileTreeRootURL"];
- (void)changeURL:(NSURL *)url {
if (url != nil) {
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString]
forKey:@"fileTreeRootURL"];
}
}
- (void)pathControlAction:(id)sender
{
if ([pathControl clickedPathComponentCell] != nil && [[pathControl clickedPathComponentCell] URL] != nil)
{
[self changeURL:[[pathControl clickedPathComponentCell] URL]];
- (void)pathControlAction:(id)sender {
NSPathControlItem *item = [self.pathControl clickedPathItem];
if (item != nil && item.URL != nil) {
[self changeURL:item.URL];
}
}
- (NSURL *)rootURL
{
- (NSURL *)rootURL {
return [rootNode URL];
}
- (void)setRootURL: (NSURL *)rootURL
{
if (![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]])
rootURL = [NSURL fileURLWithPath:[@"~/Music" stringByExpandingTildeInPath]];
- (void)setRootURL:(NSURL *)rootURL {
if (![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]]) {
rootURL = defaultMusicDirectory();
}
rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL];
[watcher setPath:[rootURL path]];
[self.watcher setPath:[rootURL path]];
[self reloadPathNode:rootNode];
}
- (PathNode *)nodeForPath:(NSString *)path
{
- (PathNode *)nodeForPath:(NSString *)path {
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(@"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]) {
@ -100,8 +107,7 @@
}
}
if (!found)
{
if (!found) {
DLog(@"Not found!");
return nil;
}
@ -110,8 +116,7 @@
return node;
}
- (void)pathDidChange:(NSString *)path
{
- (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];
@ -120,63 +125,41 @@
[self reloadPathNode:node];
}
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
PathNode *n = (item == nil ? rootNode : item);
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);
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);
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);
return n;
}
//Drag it drop it
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard {
//Get selected paths
NSMutableArray *urls = [NSMutableArray arrayWithCapacity:[items count]];
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;
- (id <NSPasteboardWriting>)outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item {
NSPasteboardItem *paste = [[NSPasteboardItem alloc] init];
[paste setData:[[item URL] dataRepresentation] forType:NSPasteboardTypeFileURL];
return paste;
}
- (void)reloadPathNode:(PathNode *)item
{
if (item == rootNode)
{
[outlineView reloadData];
}
else
{
[outlineView reloadItem:item reloadChildren:YES];
- (void)reloadPathNode:(PathNode *)item {
if (item == rootNode) {
[self.outlineView reloadData];
} else {
[self.outlineView reloadItem:item reloadChildren:YES];
}
}

View File

@ -1,7 +1,7 @@
#import <Cocoa/Cocoa.h>
extern NSString *CogPlaylistItemType;
extern NSString *CogDNDIndexType;
extern NSString *CogUrlsPboardType;
extern NSString *iTunesDropType;
@ -12,13 +12,17 @@ extern NSString *iTunesDropType;
// table view drag and drop support
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView
pasteboardWriterForRow:(NSInteger)row;
- (void)tableView:(NSTableView *)tableView
draggingSession:(NSDraggingSession *)session
willBeginAtPoint:(NSPoint)screenPoint
forRowIndexes:(NSIndexSet *)rowIndexes;
- (NSDragOperation)tableView:(NSTableView *)tableView
validateDrop:(id <NSDraggingInfo>)info
proposedRow:(int)row
proposedRow:(NSInteger)row
proposedDropOperation:(NSTableViewDropOperation)dropOperation;
- (BOOL)tableView:(NSTableView *)tableView
acceptDrop:(id <NSDraggingInfo>)info
row:(int)row
row:(NSInteger)row
dropOperation:(NSTableViewDropOperation)dropOperation;
// utility methods

View File

@ -3,45 +3,43 @@
#import "Logging.h"
NSString *CogDNDIndexType = @"org.cogx.cog.dnd-index";
NSString *CogUrlsPboardType = @"org.cogx.cog.url";
NSString *iTunesDropType = @"com.apple.tv.metadata";
@implementation DNDArrayController
NSString *CogPlaylistItemType = @"org.cogx.cog.playlist-item";
NSString *CogUrlsPboardType = @"COG_URLS_TYPE";
// @"CorePasteboardFlavorType 0x6974756E" is the "itun" type representing an iTunes plist
NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
- (void)awakeFromNib
{
- (void)awakeFromNib {
[super awakeFromNib];
// register for drag and drop
[self.tableView registerForDraggedTypes:@[CogPlaylistItemType, CogUrlsPboardType,
NSFilenamesPboardType, iTunesDropType]];
[self.tableView registerForDraggedTypes:@[CogDNDIndexType,
CogUrlsPboardType,
NSPasteboardTypeFileURL,
iTunesDropType]];
}
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView
pasteboardWriterForRow:(NSInteger)row
{
pasteboardWriterForRow:(NSInteger)row {
NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
[item setString:[@(row) stringValue] forType:CogPlaylistItemType];
[item setString:[@(row) stringValue] forType:CogDNDIndexType];
return item;
}
- (void)tableView:(NSTableView *)tableView
draggingSession:(NSDraggingSession *)session
willBeginAtPoint:(NSPoint)screenPoint
forRowIndexes:(NSIndexSet *)rowIndexes
{
forRowIndexes:(NSIndexSet *)rowIndexes {
DLog(@"Drag session started with indexes: %@", rowIndexes);
}
- (NSDragOperation)tableView:(NSTableView*)tableView
- (NSDragOperation)tableView:(NSTableView *)tableView
validateDrop:(id <NSDraggingInfo>)info
proposedRow:(int)row
proposedDropOperation:(NSTableViewDropOperation)dropOperation
{
proposedRow:(NSInteger)row
proposedDropOperation:(NSTableViewDropOperation)dropOperation {
NSDragOperation dragOp = NSDragOperationCopy;
if ([info draggingSource] == tableView)
@ -56,11 +54,10 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
}
- (BOOL)tableView:(NSTableView*)tableView
- (BOOL)tableView:(NSTableView *)tableView
acceptDrop:(id <NSDraggingInfo>)info
row:(int)row
dropOperation:(NSTableViewDropOperation)dropOperation
{
row:(NSInteger)row
dropOperation:(NSTableViewDropOperation)dropOperation {
if (row < 0) {
row = 0;
}
@ -70,12 +67,12 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
if ([info draggingSource] == tableView || items == nil) {
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSPasteboardItem *item in items) {
[indexSet addIndex:[[item stringForType:CogPlaylistItemType] intValue]];
[indexSet addIndex:(NSUInteger) [[item stringForType:CogDNDIndexType] intValue]];
}
if ([indexSet count] > 0) {
DLog(@"INDEX SET ON DROP: %@", indexSet);
NSArray *selected = [[self arrangedObjects] objectsAtIndexes:indexSet];
[self moveObjectsInArrangedObjectsFromIndexes:indexSet toIndex:row];
[self moveObjectsInArrangedObjectsFromIndexes:indexSet toIndex:(unsigned int) row];
[self setSelectedObjects:selected];
@ -88,26 +85,25 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E";
}
-(void) moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet
toIndex:(unsigned int)insertIndex
{
- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet
toIndex:(unsigned int)insertIndex {
NSArray *objects = [self arrangedObjects];
NSUInteger index = [indexSet lastIndex];
int aboveInsertIndexCount = 0;
NSUInteger aboveInsertIndexCount = 0;
id object;
int removeIndex;
NSUInteger removeIndex;
while (NSNotFound != index) {
if (index >= insertIndex) {
removeIndex = (int)(index + aboveInsertIndexCount);
removeIndex = index + aboveInsertIndexCount;
aboveInsertIndexCount += 1;
} else {
removeIndex = (int)index;
removeIndex = index;
insertIndex -= 1;
}
object = [objects objectAtIndex:removeIndex];
object = objects[removeIndex];
[self removeObjectAtArrangedObjectIndex:removeIndex];
[self insertObject:object atArrangedObjectIndex:insertIndex];

View File

@ -15,31 +15,25 @@
@class SpotlightWindowController;
@class PlaybackController;
typedef enum {
RepeatNone = 0,
RepeatOne,
RepeatAlbum,
RepeatAll
} RepeatMode;
typedef NS_ENUM(NSInteger, RepeatMode) {
RepeatModeNoRepeat = 0,
RepeatModeRepeatOne,
RepeatModeRepeatAlbum,
RepeatModeRepeatAll
};
static inline BOOL IsRepeatOneSet()
{
return [[NSUserDefaults standardUserDefaults] integerForKey:@"repeat"] == RepeatOne;
static inline BOOL IsRepeatOneSet() {
return [[NSUserDefaults standardUserDefaults] integerForKey:@"repeat"] == RepeatModeRepeatOne;
}
typedef enum {
ShuffleOff = 0,
ShuffleAlbums,
ShuffleAll
} ShuffleMode;
typedef enum { ShuffleOff = 0, ShuffleAlbums, ShuffleAll } ShuffleMode;
typedef enum {
typedef NS_ENUM(NSInteger, URLOrigin) {
URLOriginInternal = 0,
URLOriginExternal,
} URLOrigin;
URLOriginExternal
};
@interface PlaylistController : DNDArrayController {
@interface PlaylistController : DNDArrayController <NSTableViewDelegate> {
IBOutlet PlaylistLoader *playlistLoader;
IBOutlet SpotlightWindowController *spotlightWindowController;
IBOutlet PlaybackController *playbackController;
@ -57,13 +51,12 @@ typedef enum {
@property(nonatomic, retain) PlaylistEntry *currentEntry;
@property(retain) NSString *totalTime;
//Private Methods
// Private Methods
- (void)updateTotalTime;
- (void)updatePlaylistIndexes;
- (IBAction)stopAfterCurrent:(id)sender;
//PUBLIC METHODS
// PUBLIC METHODS
- (void)setShuffle:(ShuffleMode)s;
- (ShuffleMode)shuffle;
- (void)setRepeat:(RepeatMode)r;
@ -95,7 +88,7 @@ typedef enum {
- (IBAction)searchByArtist:(id)sender;
- (IBAction)searchByAlbum:(id)sender;
//FUN PLAYLIST MANAGEMENT STUFF!
// FUN PLAYLIST MANAGEMENT STUFF!
- (BOOL)next;
- (BOOL)prev;
@ -107,12 +100,15 @@ typedef enum {
- (PlaylistEntry *)entryAtIndex:(int)i;
// Event inlets:
- (void)willInsertURLs:(NSArray*)urls origin:(URLOrigin)origin;
- (void)didInsertURLs:(NSArray*)urls origin:(URLOrigin)origin;
- (void)willInsertURLs:(NSArray *)urls origin:(URLOrigin)origin;
- (void)didInsertURLs:(NSArray *)urls origin:(URLOrigin)origin;
// queue methods
- (IBAction)toggleQueued:(id)sender;
- (IBAction)emptyQueueList:(id)sender;
- (NSMutableArray *)queueList;
- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet
toIndex:(unsigned int)insertIndex;
@end

File diff suppressed because it is too large Load Diff

View File

@ -7,13 +7,11 @@
//
#import "PlaylistView.h"
#import "PlaybackController.h"
#import "PlaylistController.h"
#import "IndexFormatter.h"
#import "SecondsFormatter.h"
#import "BlankZeroFormatter.h"
#import "IndexFormatter.h"
#import "PlaylistEntry.h"
#import "SecondsFormatter.h"
#import "CogAudio/Status.h"
@ -21,8 +19,7 @@
@implementation PlaylistView
- (void)awakeFromNib
{
- (void)awakeFromNib {
[[self menu] setAutoenablesItems:NO];
// Configure bindings to scale font size and row height
@ -35,7 +32,7 @@
[[col dataCell] setFont:f];
}
//Set up formatters
// Set up formatters
NSFormatter *secondsFormatter = [[SecondsFormatter alloc] init];
[[[self tableColumnWithIdentifier:@"length"] dataCell] setFormatter:secondsFormatter];
@ -45,39 +42,38 @@
NSFormatter *blankZeroFormatter = [[BlankZeroFormatter alloc] init];
[[[self tableColumnWithIdentifier:@"track"] dataCell] setFormatter:blankZeroFormatter];
[[[self tableColumnWithIdentifier:@"year"] dataCell] setFormatter:blankZeroFormatter];
//end setting up formatters
// end setting up formatters
[self setVerticalMotionCanBeginDrag:YES];
//Set up header context menu
// Set up header context menu
headerContextMenu = [[NSMenu alloc] initWithTitle:@"Playlist Header Context Menu"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"identifier" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"identifier"
ascending:YES];
NSArray *sortDescriptors = @[sortDescriptor];
int visibleTableColumns = 0;
int menuIndex = 0;
for (NSTableColumn *col in [[self tableColumns] sortedArrayUsingDescriptors: sortDescriptors])
{
for (NSTableColumn *col in [[self tableColumns] sortedArrayUsingDescriptors:sortDescriptors]) {
NSString *title;
if ([[col identifier] isEqualToString:@"status"])
{
if ([[col identifier] isEqualToString:@"status"]) {
title = @"Status";
}
else if ([[col identifier] isEqualToString:@"index"])
{
} else if ([[col identifier] isEqualToString:@"index"]) {
title = @"Index";
}
else
{
} else {
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 setRepresentedObject:col];
[contextMenuItem setState:([col isHidden] ? NSOffState : NSOnState)];
[contextMenuItem setState:([col isHidden] ? NSControlStateValueOff : NSControlStateValueOn)];
visibleTableColumns += ![col isHidden];
menuIndex++;
@ -92,79 +88,65 @@
[[self headerView] setMenu:headerContextMenu];
}
- (IBAction)toggleColumn:(id)sender
{
- (IBAction)toggleColumn:(id)sender {
id tc = [sender representedObject];
if ([sender state] == NSOffState)
{
[sender setState:NSOnState];
if ([sender state] == NSControlStateValueOff) {
[sender setState:NSControlStateValueOn];
[tc setHidden: NO];
}
else
{
[sender setState:NSOffState];
[tc setHidden:NO];
} else {
[sender setState:NSControlStateValueOff];
[tc setHidden: YES];
[tc setHidden:YES];
}
}
- (BOOL)acceptsFirstResponder
{
- (BOOL)acceptsFirstResponder {
return YES;
}
- (BOOL)resignFirstResponder
{
- (BOOL)resignFirstResponder {
return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent *)mouseDownEvent
{
- (BOOL)acceptsFirstMouse:(NSEvent *)mouseDownEvent {
return NO;
}
- (void)mouseDown:(NSEvent *)e
{
- (void)mouseDown:(NSEvent *)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];
}
}
// enables right-click selection for "Show in Finder" contextual menu
-(NSMenu*)menuForEvent:(NSEvent*)event
{
//Find which row is under the cursor
- (NSMenu *)menuForEvent:(NSEvent *)event {
// Find which row is under the cursor
[[self window] makeFirstResponder:self];
NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
NSInteger iRow = [self rowAtPoint:menuPoint];
NSMenu* tableViewMenu = [self menu];
NSMenu *tableViewMenu = [self menu];
/* Update the table selection before showing menu
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 */
BOOL currentRowIsSelected = [[self selectedRowIndexes] containsIndex:iRow];
BOOL currentRowIsSelected = [[self selectedRowIndexes] containsIndex:(NSUInteger) iRow];
if (!currentRowIsSelected) {
if (iRow == -1)
{
if (iRow == -1) {
[self deselectAll:self];
}
else
{
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:iRow] byExtendingSelection:NO];
} else {
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:(NSUInteger) iRow] byExtendingSelection:NO];
}
}
if ([self numberOfSelectedRows] <=0)
{
//No rows are selected, so the table should be displayed with all items disabled
if ([self numberOfSelectedRows] <= 0) {
// No rows are selected, so the table should be displayed with all items disabled
int i;
for (i=0;i<[tableViewMenu numberOfItems];i++) {
for (i = 0; i < [tableViewMenu numberOfItems]; i++) {
[[tableViewMenu itemAtIndex:i] setEnabled:NO];
}
}
@ -172,141 +154,152 @@
return tableViewMenu;
}
- (void)keyDown:(NSEvent *)e
{
unsigned int modifiers = [e modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagShift | NSEventModifierFlagControl | NSEventModifierFlagOption);
- (void)keyDown:(NSEvent *)e {
unsigned int modifiers =
[e modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagShift |
NSEventModifierFlagControl | NSEventModifierFlagOption);
NSString *characters = [e characters];
unichar c;
if ([characters length] != 1)
{
if ([characters length] != 1) {
[super keyDown:e];
return;
}
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];
}
else if (modifiers == 0 && c == ' ')
{
} else if (modifiers == 0 && c == ' ') {
[playbackController playPauseResume:self];
}
else if (modifiers == 0 && (c == NSEnterCharacter || c == NSCarriageReturnCharacter))
{
} else if (modifiers == 0 && (c == NSEnterCharacter || c == NSCarriageReturnCharacter)) {
[playbackController play:self];
}
else if (modifiers == 0 && c == NSLeftArrowFunctionKey)
{
} else if (modifiers == 0 && c == NSLeftArrowFunctionKey) {
[playbackController eventSeekBackward:self];
}
else if (modifiers == 0 && c == NSRightArrowFunctionKey)
{
} else if (modifiers == 0 && c == NSRightArrowFunctionKey) {
[playbackController eventSeekForward:self];
}
// Escape
else if (modifiers == 0 && c == 0x1b)
{
else if (modifiers == 0 && c == 0x1b) {
[playlistController clearFilterPredicate:self];
}
else
{
} else {
[super keyDown:e];
}
}
- (IBAction)scrollToCurrentEntry:(id)sender
{
- (IBAction)scrollToCurrentEntry:(id)sender {
[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];
}
- (IBAction)redo:(id)sender
{
- (IBAction)redo:(id)sender {
[[playlistController undoManager] redo];
}
- (IBAction)copy:(id)sender
{
- (IBAction)copy:(id)sender {
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
[pboard clearContents];
NSMutableArray *selectedURLs = [[NSMutableArray alloc] init];
NSArray *entries =
[[playlistController content] objectsAtIndexes:[playlistController selectionIndexes]];
NSUInteger capacity = [entries count];
NSMutableArray *selectedURLs = [NSMutableArray arrayWithCapacity:capacity];
for (PlaylistEntry *pe in [[playlistController content] objectsAtIndexes:[playlistController selectionIndexes]])
{
for (PlaylistEntry *pe in entries) {
[selectedURLs addObject:[pe URL]];
}
[pboard setData:[NSArchiver archivedDataWithRootObject:selectedURLs] forType:CogUrlsPboardType];
NSError *error;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:selectedURLs
requiringSecureCoding:YES
error:&error];
if (!data) {
DLog(@"Error: %@", error);
}
[pboard setData:data forType:CogUrlsPboardType];
NSMutableDictionary * tracks = [[NSMutableDictionary alloc] init];
NSMutableDictionary *tracks = [NSMutableDictionary dictionaryWithCapacity:capacity];
unsigned long i = 0;
for (NSURL *url in selectedURLs)
{
NSMutableDictionary * track = [NSMutableDictionary dictionaryWithObjectsAndKeys:[url absoluteString], @"Location", nil];
[tracks setObject:track forKey:[NSString stringWithFormat:@"%lu", i]];
++i;
for (NSURL *url in selectedURLs) {
tracks[[NSString stringWithFormat:@"%lu", i++]] = @{@"Location": [url absoluteString]};
}
NSMutableDictionary * itunesPlist = [NSMutableDictionary dictionaryWithObjectsAndKeys:tracks, @"Tracks", nil];
NSDictionary *itunesPlist = @{@"Tracks": tracks};
[pboard setPropertyList:itunesPlist forType:iTunesDropType];
NSMutableArray *filePaths = [[NSMutableArray alloc] init];
NSMutableArray *filePaths = [NSMutableArray array];
for (NSURL *url in selectedURLs)
{
if ([url isFileURL])
[filePaths addObject:[url path]];
for (NSURL *url in selectedURLs) {
if ([url isFileURL]) {
[filePaths addObject:url];
}
}
if ([filePaths count])
[pboard setPropertyList:filePaths forType:NSFilenamesPboardType];
if ([filePaths count]) {
[pboard writeObjects:filePaths];
}
}
- (IBAction)cut:(id)sender
{
- (IBAction)cut:(id)sender {
[self copy:sender];
[playlistController removeObjectsAtArrangedObjectIndexes:[playlistController selectionIndexes]];
if ([playlistController shuffle] != ShuffleOff)
[playlistController resetShuffleList];
if ([playlistController shuffle] != ShuffleOff) [playlistController resetShuffleList];
}
- (IBAction)paste:(id)sender
{
- (IBAction)paste:(id)sender {
// 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];
NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
NSPasteboardType bestType = [pboard availableTypeFromArray:supportedTypes];
DLog(@"All types:");
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 alloc] init];
NSMutableArray *acceptedURLs = [NSMutableArray array];
// Get files from an file drawer drop
if ([bestType isEqualToString:CogUrlsPboardType]) {
NSArray *urls = [NSUnarchiver unarchiveObjectWithData:[pboard dataForType:CogUrlsPboardType]];
NSError *error;
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];
[acceptedURLs addObjectsFromArray:urls];
}
// Get files from a normal file drop (such as from Finder)
if ([bestType isEqualToString:NSFilenamesPboardType]) {
if ([bestType isEqualToString:NSPasteboardTypeFileURL]) {
NSMutableArray *urls = [[NSMutableArray alloc] init];
for (NSString *file in [pboard propertyListForType:NSFilenamesPboardType])
{
for (NSString *file in [pboard propertyListForType:NSPasteboardTypeFileURL]) {
[urls addObject:[NSURL fileURLWithPath:file]];
}
@ -330,66 +323,47 @@
[acceptedURLs addObjectsFromArray:urls];
}
if ([acceptedURLs count])
{
if ([acceptedURLs count]) {
NSUInteger row = [[playlistController content] count];
[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];
if ([playlistController shuffle] != ShuffleOff)
[playlistController resetShuffleList];
if ([playlistController shuffle] != ShuffleOff) [playlistController resetShuffleList];
}
}
- (IBAction)delete:(id)sender
{
- (IBAction)delete:(id)sender {
[playlistController removeObjectsAtArrangedObjectIndexes:[playlistController selectionIndexes]];
}
-(BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
{
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem {
SEL action = [anItem action];
if (action == @selector(undo:))
{
if ([[playlistController undoManager] canUndo])
return YES;
else
return NO;
if (action == @selector(undo:)) {
return [[playlistController undoManager] canUndo];
}
if (action == @selector(redo:))
{
if ([[playlistController undoManager] canRedo])
return YES;
else
return NO;
if (action == @selector(redo:)) {
return [[playlistController undoManager] canRedo];
}
if (action == @selector(cut:) || action == @selector(copy:) || action == @selector(delete:))
{
if ([[playlistController selectionIndexes] count] == 0)
return NO;
else
return YES;
if (action == @selector(cut:) || action == @selector(copy:) || action == @selector(delete:)) {
return [[playlistController selectionIndexes] count] != 0;
}
if (action == @selector(paste:))
{
if (action == @selector(paste:)) {
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
NSArray *supportedTypes = [NSArray arrayWithObjects:CogUrlsPboardType, NSFilenamesPboardType, iTunesDropType, nil];
NSArray *supportedTypes = @[CogUrlsPboardType, NSPasteboardTypeFileURL, iTunesDropType];
NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
if (bestType != nil)
return YES;
else
return NO;
return bestType != nil;
}
if (action == @selector(scrollToCurrentEntry:) && (([playbackController playbackStatus] == kCogStatusStopped) || ([playbackController playbackStatus] == kCogStatusStopping)))
if (action == @selector(scrollToCurrentEntry:) &&
(([playbackController playbackStatus] == kCogStatusStopped) ||
([playbackController playbackStatus] == kCogStatusStopping)))
return NO;
return [super validateUserInterfaceItem:anItem];
@ -405,5 +379,4 @@
}
#endif
@end

View File

@ -8,9 +8,7 @@
#import <Cocoa/Cocoa.h>
@interface XmlContainer : NSObject {
}
@interface XmlContainer : NSObject
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename;

View File

@ -8,17 +8,13 @@
#import "XmlContainer.h"
#import "PlaylistEntry.h"
#import "Logging.h"
@implementation XmlContainer
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename
{
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename {
NSRange protocolRange = [path rangeOfString:@"://"];
if (protocolRange.location != NSNotFound)
{
if (protocolRange.location != NSNotFound) {
return [NSURL URLWithString:path];
}
@ -32,8 +28,7 @@
NSString *possibleFragment;
[scanner scanUpToString:@"#" intoString:nil];
if ([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd])
{
if ([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd]) {
fragment = possibleFragment;
[unixPath deleteCharactersInRange:NSMakeRange([scanner scanLocation] - [possibleFragment length], [possibleFragment length])];
break;
@ -51,29 +46,35 @@
}
//Append the fragment
NSURL *url = [NSURL URLWithString:[[[NSURL fileURLWithPath:unixPath] absoluteString] stringByAppendingString: fragment]];
NSURL *url = [NSURL URLWithString:[[[NSURL fileURLWithPath:unixPath] absoluteString] stringByAppendingString:fragment]];
return url;
}
+ (NSDictionary *)entriesForContainerURL:(NSURL *)url
{
+ (NSDictionary *)entriesForContainerURL:(NSURL *)url {
if (![url isFileURL])
return [NSDictionary dictionary];
return nil;
NSError *nserr;
NSString *error;
NSError *error;
NSString *filename = [url path];
NSString * contents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:&nserr];
NSString *contents = [NSString stringWithContentsOfFile:filename
encoding:NSUTF8StringEncoding
error:&error];
if (!contents) {
ALog(@"Error: %@", error);
return nil;
}
NSData* plistData = [contents dataUsingEncoding:NSUTF8StringEncoding];
NSData *plistData = [contents dataUsingEncoding:NSUTF8StringEncoding];
NSPropertyListFormat format;
id plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if(!plist){
ALog(@"Error: %@",error);
id plist = [NSPropertyListSerialization propertyListWithData:plistData
options:NSPropertyListImmutable
format:&format
error:&error];
if (!plist) {
ALog(@"Error: %@", error);
return nil;
}
@ -82,27 +83,34 @@
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"];
NSArray *items;
NSDictionary *albumArt;
NSArray *queueList;
if (isArray) {
items = (NSArray *) plist;
albumArt = nil;
queueList = [NSArray array];
} else {
NSDictionary *dict = (NSDictionary *) plist;
items = dict[@"items"];
albumArt = dict[@"albumArt"];
queueList = dict[@"queue"];
}
NSMutableArray *entries = [NSMutableArray array];
for (NSDictionary *entry in items)
{
NSMutableDictionary * preparedEntry = [NSMutableDictionary dictionaryWithDictionary:entry];
for (NSDictionary *entry in items) {
NSMutableDictionary *preparedEntry = [NSMutableDictionary dictionaryWithDictionary:entry];
[preparedEntry setObject:[self urlForPath:[preparedEntry objectForKey:@"URL"] relativeTo:filename] forKey:@"URL"];
preparedEntry[@"URL"] = [self urlForPath:preparedEntry[@"URL"] relativeTo:filename];
if (albumArt && [preparedEntry objectForKey:@"albumArt"])
[preparedEntry setObject:[albumArt objectForKey:[preparedEntry objectForKey:@"albumArt"]] forKey:@"albumArt"];
if (albumArt && preparedEntry[@"albumArt"])
preparedEntry[@"albumArt"] = albumArt[preparedEntry[@"albumArt"]];
[entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]];
}
return [NSDictionary dictionaryWithObjectsAndKeys:entries, @"entries", queueList, @"queue", nil];
return @{@"entries": entries, @"queue": queueList};
}
@end

View File

@ -10,9 +10,7 @@
#import "PlaylistController.h"
@interface RepeatModeTransformer : NSValueTransformer {
RepeatMode repeatMode;
}
@interface RepeatModeTransformer : NSValueTransformer
- (id)initWithMode:(RepeatMode) r;

View File

@ -7,20 +7,19 @@
//
#import "RepeatTransformers.h"
#import "PlaylistController.h"
#import "Logging.h"
@implementation RepeatModeTransformer
@implementation RepeatModeTransformer {
RepeatMode repeatMode;
}
+ (Class)transformedValueClass { return [NSNumber class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)initWithMode:(RepeatMode) r
{
- (id)initWithMode:(RepeatMode)r {
self = [super init];
if (self)
{
if (self) {
repeatMode = r;
}
@ -35,12 +34,7 @@
RepeatMode mode = (RepeatMode) [value integerValue];
if (repeatMode == mode) {
return [NSNumber numberWithBool:YES];
}
return [NSNumber numberWithBool:NO];
return @(repeatMode == mode);
}
- (id)reverseTransformedValue:(id)value {
@ -48,13 +42,11 @@
BOOL enabled = [value boolValue];
if (enabled) {
return [NSNumber numberWithInt:repeatMode];
}
else if(repeatMode == RepeatNone) {
return [NSNumber numberWithInt:RepeatAll];
}
else {
return [NSNumber numberWithInt:RepeatNone];
return @(repeatMode);
} else if (repeatMode == RepeatModeNoRepeat) {
return @(RepeatModeRepeatAll);
} else {
return @(RepeatModeNoRepeat);
}
}
@ -73,16 +65,16 @@
RepeatMode mode = (RepeatMode) [value integerValue];
if (mode == RepeatNone) {
if (mode == RepeatModeNoRepeat) {
return [NSImage imageNamed:@"repeatModeOffTemplate"];
}
else if (mode == RepeatOne) {
else if (mode == RepeatModeRepeatOne) {
return [NSImage imageNamed:@"repeatModeOneTemplate"];
}
else if (mode == RepeatAlbum) {
else if (mode == RepeatModeRepeatAlbum) {
return [NSImage imageNamed:@"repeatModeAlbumTemplate"];
}
else if (mode == RepeatAll) {
else if (mode == RepeatModeRepeatAll) {
return [NSImage imageNamed:@"repeatModeAllTemplate"];
}