You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

314 lines
12 KiB

/*****************************************************************************
* VLCLibraryVideoTableViewDataSource.m: MacOS X interface module
*****************************************************************************
* Copyright (C) 2019 VLC authors and VideoLAN
*
* Authors: Felix Paul Kühne <fkuehne # videolan -dot- org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#import "VLCLibraryVideoTableViewDataSource.h"
#import "library/VLCLibraryCollectionViewFlowLayout.h"
#import "library/VLCLibraryCollectionViewItem.h"
#import "library/VLCLibraryCollectionViewMediaItemSupplementaryDetailView.h"
#import "library/VLCLibraryCollectionViewSupplementaryElementView.h"
#import "library/VLCLibraryModel.h"
#import "library/VLCLibraryDataTypes.h"
#import "library/VLCLibraryTableCellView.h"
#import "library/video-library/VLCLibraryVideoGroupDescriptor.h"
#import "main/CompatibilityFixes.h"
#import "extensions/NSString+Helpers.h"
#import "extensions/NSPasteboardItem+VLCAdditions.h"
@interface VLCLibraryVideoTableViewDataSource ()
{
NSArray *_recentsArray;
NSArray *_libraryArray;
VLCLibraryCollectionViewFlowLayout *_collectionViewFlowLayout;
}
@end
@implementation VLCLibraryVideoTableViewDataSource
- (instancetype)init
{
self = [super init];
if(self) {
NSNotificationCenter *notificationCenter = NSNotificationCenter.defaultCenter;
[notificationCenter addObserver:self
selector:@selector(libraryModelVideoListReset:)
name:VLCLibraryModelVideoMediaListReset
object:nil];
[notificationCenter addObserver:self
selector:@selector(libraryModelVideoItemUpdated:)
name:VLCLibraryModelVideoMediaItemUpdated
object:nil];
[notificationCenter addObserver:self
selector:@selector(libraryModelVideoItemDeleted:)
name:VLCLibraryModelVideoMediaItemDeleted
object:nil];
[notificationCenter addObserver:self
selector:@selector(libraryModelRecentsListReset:)
name:VLCLibraryModelRecentsMediaListReset
object:nil];
[notificationCenter addObserver:self
selector:@selector(libraryModelRecentsItemUpdated:)
name:VLCLibraryModelRecentsMediaItemUpdated
object:nil];
[notificationCenter addObserver:self
selector:@selector(libraryModelRecentsItemDeleted:)
name:VLCLibraryModelRecentsMediaItemDeleted
object:nil];
}
return self;
}
- (NSUInteger)indexOfMediaItem:(const NSUInteger)libraryId inArray:(NSArray const *)array
{
return [array indexOfObjectPassingTest:^BOOL(VLCMediaLibraryMediaItem * const findMediaItem, const NSUInteger idx, BOOL * const stop) {
NSAssert(findMediaItem != nil, @"Collection should not contain nil media items");
return findMediaItem.libraryID == libraryId;
}];
}
- (void)libraryModelVideoListReset:(NSNotification * const)aNotification
{
if (_groupsTableView.selectedRow == -1 ||
_groupsTableView.selectedRow != VLCLibraryVideoLibraryGroup - 1) { // Row 0 == second value in enum, so compensate
return;
}
[self reloadData];
}
- (void)libraryModelVideoItemUpdated:(NSNotification * const)aNotification
{
if (_groupsTableView.selectedRow == -1 ||
_groupsTableView.selectedRow != VLCLibraryVideoLibraryGroup - 1) { // Row 0 == second value in enum, so compensate
return;
}
NSParameterAssert(aNotification);
VLCMediaLibraryMediaItem *notificationMediaItem = aNotification.object;
NSAssert(notificationMediaItem != nil, @"Media item updated notification should carry valid media item");
[self reloadDataForMediaItem:notificationMediaItem
inVideoGroup:VLCLibraryVideoLibraryGroup];
}
- (void)libraryModelVideoItemDeleted:(NSNotification * const)aNotification
{
if (_groupsTableView.selectedRow == -1 ||
_groupsTableView.selectedRow != VLCLibraryVideoLibraryGroup - 1) { // Row 0 == second value in enum, so compensate
return;
}
NSParameterAssert(aNotification);
VLCMediaLibraryMediaItem *notificationMediaItem = aNotification.object;
NSAssert(notificationMediaItem != nil, @"Media item deleted notification should carry valid media item");
[self deleteDataForMediaItem:notificationMediaItem
inVideoGroup:VLCLibraryVideoLibraryGroup];
}
- (void)libraryModelRecentsListReset:(NSNotification * const)aNotification
{
if (_groupsTableView.selectedRow == -1 ||
_groupsTableView.selectedRow != VLCLibraryVideoRecentsGroup - 1) { // Row 0 == second value in enum, so compensate
return;
}
[self reloadData];
}
- (void)libraryModelRecentsItemUpdated:(NSNotification * const)aNotification
{
if (_groupsTableView.selectedRow == -1 ||
_groupsTableView.selectedRow != VLCLibraryVideoRecentsGroup - 1) { // Row 0 == second value in enum, so compensate
return;
}
NSParameterAssert(aNotification);
VLCMediaLibraryMediaItem *notificationMediaItem = aNotification.object;
NSAssert(notificationMediaItem != nil, @"Media item updated notification should carry valid media item");
[self reloadDataForMediaItem:notificationMediaItem
inVideoGroup:VLCLibraryVideoRecentsGroup];
}
- (void)libraryModelRecentsItemDeleted:(NSNotification * const)aNotification
{
if (_groupsTableView.selectedRow == -1 ||
_groupsTableView.selectedRow != VLCLibraryVideoRecentsGroup - 1) { // Row 0 == second value in enum, so compensate
return;
}
NSParameterAssert(aNotification);
VLCMediaLibraryMediaItem *notificationMediaItem = aNotification.object;
NSAssert(notificationMediaItem != nil, @"Media item deleted notification should carry valid media item");
[self deleteDataForMediaItem:notificationMediaItem
inVideoGroup:VLCLibraryVideoRecentsGroup];
}
- (void)reloadData
{
if(!_libraryModel) {
return;
}
[_collectionViewFlowLayout resetLayout];
self->_recentsArray = [self.libraryModel listOfRecentMedia];
self->_libraryArray = [self.libraryModel listOfVideoMedia];
[self->_groupSelectionTableView reloadData];
}
- (void)changeDataForSpecificMediaItem:(VLCMediaLibraryMediaItem * const)mediaItem
inVideoGroup:(VLCLibraryVideoGroup)group
arrayOperation:(void(^)(const NSMutableArray*, const NSUInteger))arrayOperation
completionHandler:(void(^)(const NSIndexSet*))completionHandler
{
NSMutableArray *groupMutableCopyArray;
switch(group) {
case VLCLibraryVideoLibraryGroup:
groupMutableCopyArray = [_libraryArray mutableCopy];
break;
case VLCLibraryVideoRecentsGroup:
groupMutableCopyArray = [_recentsArray mutableCopy];
break;
default:
return;
}
NSUInteger mediaItemIndex = [self indexOfMediaItem:mediaItem.libraryID inArray:groupMutableCopyArray];
if (mediaItemIndex == NSNotFound) {
return;
}
arrayOperation(groupMutableCopyArray, mediaItemIndex);
switch(group) {
case VLCLibraryVideoLibraryGroup:
_libraryArray = [groupMutableCopyArray copy];
break;
case VLCLibraryVideoRecentsGroup:
_recentsArray = [groupMutableCopyArray copy];
break;
default:
return;
}
NSIndexSet * const rowIndexSet = [NSIndexSet indexSetWithIndex:mediaItemIndex];
completionHandler(rowIndexSet);
}
- (void)reloadDataForMediaItem:(VLCMediaLibraryMediaItem * const)mediaItem
inVideoGroup:(VLCLibraryVideoGroup)group
{
[self changeDataForSpecificMediaItem:mediaItem
inVideoGroup:group
arrayOperation:^(NSMutableArray * const mediaArray, const NSUInteger mediaItemIndex) {
[mediaArray replaceObjectAtIndex:mediaItemIndex withObject:mediaItem];
} completionHandler:^(NSIndexSet * const rowIndexSet) {
// Don't regenerate the groups by index as these do not change according to the notification
// Stick to the selection table view
NSRange columnRange = NSMakeRange(0, self->_groupsTableView.numberOfColumns);
NSIndexSet * const columnIndexSet = [NSIndexSet indexSetWithIndexesInRange:columnRange];
[self->_groupSelectionTableView reloadDataForRowIndexes:rowIndexSet columnIndexes:columnIndexSet];
}];
}
- (void)deleteDataForMediaItem:(VLCMediaLibraryMediaItem * const)mediaItem
inVideoGroup:(VLCLibraryVideoGroup)group
{
[self changeDataForSpecificMediaItem:mediaItem
inVideoGroup:group
arrayOperation:^(NSMutableArray * const mediaArray, const NSUInteger mediaItemIndex) {
[mediaArray removeObjectAtIndex:mediaItemIndex];
} completionHandler:^(NSIndexSet * const rowIndexSet){
// Don't regenerate the groups by index as these do not change according to the notification
// Stick to the selection table view
[self->_groupSelectionTableView removeRowsAtIndexes:rowIndexSet withAnimation:NSTableViewAnimationSlideUp];
}];
}
#pragma mark - table view data source and delegation
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
if (tableView == _groupsTableView) {
return 2;
} else if (tableView == _groupSelectionTableView && _groupsTableView.selectedRow > -1) {
switch(_groupsTableView.selectedRow + 1) { // Group 0 is invalid so add one
case VLCLibraryVideoRecentsGroup:
return _recentsArray.count;
case VLCLibraryVideoLibraryGroup:
return _libraryArray.count;
default:
NSAssert(1, @"Reached unreachable case for video library section");
break;
}
}
return 0;
}
- (id<NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row
{
const id<VLCMediaLibraryItemProtocol> libraryItem = [self libraryItemAtRow:row forTableView:tableView];
return [NSPasteboardItem pasteboardItemWithLibraryItem:libraryItem];
}
- (id<VLCMediaLibraryItemProtocol>)libraryItemAtRow:(NSInteger)row
forTableView:(NSTableView *)tableView
{
if (tableView == _groupSelectionTableView && _groupsTableView.selectedRow > -1) {
switch(_groupsTableView.selectedRow + 1) { // Group 0 is invalid so add one
case VLCLibraryVideoRecentsGroup:
return _recentsArray[row];
case VLCLibraryVideoLibraryGroup:
return _libraryArray[row];
default:
NSAssert(1, @"Reached unreachable case for video library section");
break;
}
}
return nil;
}
@end