[vlc-devel] [VLC 3.x 06/11] macosx: Update PXSourceList to 2.x
Marvin Scholz
epirat07 at gmail.com
Wed Aug 26 00:50:12 CEST 2020
(cherry picked from commit 9de4120cf4395a0f5e24f69e3dcf41db73ae9b49)
Signed-off-by: Marvin Scholz <epirat07 at gmail.com>
---
modules/gui/macosx/Makefile.am | 23 +-
modules/gui/macosx/PXSourceList.h | 32 -
modules/gui/macosx/PXSourceList.m | 831 ------------------
.../PXSourceListDelegateDataSourceProxy.h | 21 +
.../PXSourceListDelegateDataSourceProxy.m | 470 ++++++++++
.../Internal/PXSourceListPrivateConstants.h | 18 +
.../Internal/PXSourceListRuntimeAdditions.h | 21 +
.../Internal/PXSourceListRuntimeAdditions.m | 67 ++
.../gui/macosx/PXSourceList/PXSourceList.h | 206 +++++
.../gui/macosx/PXSourceList/PXSourceList.m | 578 ++++++++++++
.../PXSourceList/PXSourceListBadgeCell.h | 23 +
.../PXSourceList/PXSourceListBadgeCell.m | 122 +++
.../PXSourceList/PXSourceListBadgeView.h | 72 ++
.../PXSourceList/PXSourceListBadgeView.m | 52 ++
.../PXSourceList/PXSourceListDataSource.h | 396 +++++++++
.../PXSourceList/PXSourceListDelegate.h | 522 +++++++++++
.../macosx/PXSourceList/PXSourceListItem.h | 228 +++++
.../macosx/PXSourceList/PXSourceListItem.m | 101 +++
.../PXSourceList/PXSourceListTableCellView.h | 43 +
.../PXSourceList/PXSourceListTableCellView.m | 31 +
modules/gui/macosx/PXSourceListDataSource.h | 41 -
modules/gui/macosx/PXSourceListDelegate.h | 63 --
modules/gui/macosx/SideBarItem.h | 50 --
modules/gui/macosx/SideBarItem.m | 70 --
modules/gui/macosx/VLCMainWindow.m | 34 +-
modules/gui/macosx/VLCPlaylist.h | 1 -
modules/gui/macosx/VLCPlaylist.m | 4 +-
modules/gui/macosx/VLCSourceListItem.h | 34 +
modules/gui/macosx/VLCSourceListItem.m | 28 +
29 files changed, 3072 insertions(+), 1110 deletions(-)
delete mode 100644 modules/gui/macosx/PXSourceList.h
delete mode 100644 modules/gui/macosx/PXSourceList.m
create mode 100755 modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.h
create mode 100755 modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.m
create mode 100755 modules/gui/macosx/PXSourceList/Internal/PXSourceListPrivateConstants.h
create mode 100755 modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.h
create mode 100755 modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.m
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceList.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceList.m
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.m
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListBadgeView.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListBadgeView.m
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListDataSource.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListDelegate.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListItem.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListItem.m
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListTableCellView.h
create mode 100755 modules/gui/macosx/PXSourceList/PXSourceListTableCellView.m
delete mode 100644 modules/gui/macosx/PXSourceListDataSource.h
delete mode 100644 modules/gui/macosx/PXSourceListDelegate.h
delete mode 100644 modules/gui/macosx/SideBarItem.h
delete mode 100644 modules/gui/macosx/SideBarItem.m
create mode 100644 modules/gui/macosx/VLCSourceListItem.h
create mode 100644 modules/gui/macosx/VLCSourceListItem.m
diff --git a/modules/gui/macosx/Makefile.am b/modules/gui/macosx/Makefile.am
index 050ee0a456..9957a27c2a 100644
--- a/modules/gui/macosx/Makefile.am
+++ b/modules/gui/macosx/Makefile.am
@@ -50,9 +50,6 @@ libmacosx_plugin_la_SOURCES = \
gui/macosx/VLCPLModel.h gui/macosx/VLCPLModel.m \
gui/macosx/prefs.h gui/macosx/prefs.m \
gui/macosx/prefs_widgets.h gui/macosx/prefs_widgets.m \
- gui/macosx/PXSourceList.h gui/macosx/PXSourceList.m \
- gui/macosx/PXSourceListDataSource.h gui/macosx/PXSourceListDelegate.h \
- gui/macosx/SideBarItem.h gui/macosx/SideBarItem.m \
gui/macosx/VLCPopupPanelController.h gui/macosx/VLCPopupPanelController.m \
gui/macosx/VLCTextfieldPanelController.h gui/macosx/VLCTextfieldPanelController.m \
gui/macosx/VLCSimplePrefsController.h gui/macosx/VLCSimplePrefsController.m \
@@ -91,6 +88,7 @@ libmacosx_plugin_la_SOURCES = \
gui/macosx/VLCRendererItem.h gui/macosx/VLCRendererItem.m \
gui/macosx/VLCRendererMenuController.h gui/macosx/VLCRendererMenuController.m \
gui/macosx/VLCResumeDialogController.h gui/macosx/VLCResumeDialogController.m \
+ gui/macosx/VLCSourceListItem.h gui/macosx/VLCSourceListItem.m \
gui/macosx/VLCTrackSynchronizationWindowController.h gui/macosx/VLCTrackSynchronizationWindowController.m \
gui/macosx/VLCVideoEffectsWindowController.h gui/macosx/VLCVideoEffectsWindowController.m \
gui/macosx/VLCFSPanelController.h gui/macosx/VLCFSPanelController.m \
@@ -107,6 +105,25 @@ libmacosx_plugin_la_SOURCES = \
gui/macosx/VLCVolumeSliderCell.h gui/macosx/VLCVolumeSliderCell.m \
gui/macosx/VLCWrappableTextField.h gui/macosx/VLCWrappableTextField.m
+# PXSourceList sources
+libmacosx_plugin_la_SOURCES += \
+ gui/macosx/PXSourceList/PXSourceList.h \
+ gui/macosx/PXSourceList/PXSourceList.m \
+ gui/macosx/PXSourceList/PXSourceListBadgeCell.h \
+ gui/macosx/PXSourceList/PXSourceListBadgeCell.m \
+ gui/macosx/PXSourceList/PXSourceListBadgeView.h \
+ gui/macosx/PXSourceList/PXSourceListBadgeView.m \
+ gui/macosx/PXSourceList/PXSourceListItem.h \
+ gui/macosx/PXSourceList/PXSourceListItem.m \
+ gui/macosx/PXSourceList/PXSourceListTableCellView.h \
+ gui/macosx/PXSourceList/PXSourceListTableCellView.m \
+ gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.h \
+ gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.m \
+ gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.h \
+ gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.m \
+ gui/macosx/PXSourceList/Internal/PXSourceListPrivateConstants.h \
+ gui/macosx/PXSourceList/PXSourceListDataSource.h \
+ gui/macosx/PXSourceList/PXSourceListDelegate.h
# User interface compilation
diff --git a/modules/gui/macosx/PXSourceList.h b/modules/gui/macosx/PXSourceList.h
deleted file mode 100644
index 1a4182edc9..0000000000
--- a/modules/gui/macosx/PXSourceList.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// PXSourceList.h
-// PXSourceList
-//
-// Created by Alex Rozanski on 05/09/2009.
-// Copyright 2009-10 Alex Rozanski http://perspx.com
-//
-
-#import <Cocoa/Cocoa.h>
-
-#import "PXSourceListDelegate.h"
-#import "PXSourceListDataSource.h"
-
- at interface PXSourceList: NSOutlineView <NSOutlineViewDelegate, NSOutlineViewDataSource>
-{
- id <PXSourceListDelegate> _secondaryDelegate; //Used to store the publicly visible delegate
- id <PXSourceListDataSource> _secondaryDataSource; //Used to store the publicly visible data source
-}
-
- at property (nonatomic) NSSize iconSize;
-
- at property (assign) id<PXSourceListDataSource, NSOutlineViewDataSource> _Nullable dataSource;
- at property (assign) id<PXSourceListDelegate, NSOutlineViewDelegate> _Nullable delegate;
-
-- (NSUInteger)numberOfGroups; //Returns the number of groups in the Source List
-- (BOOL)isGroupItem:(nonnull id)item; //Returns whether `item` is a group
-- (BOOL)isGroupAlwaysExpanded:(nonnull id)group; //Returns whether `group` is displayed as always expanded
-
-- (BOOL)itemHasBadge:(nonnull id)item; //Returns whether `item` has a badge
-- (NSInteger)badgeValueForItem:(nonnull id)item; //Returns the badge value for `item`
-
- at end
diff --git a/modules/gui/macosx/PXSourceList.m b/modules/gui/macosx/PXSourceList.m
deleted file mode 100644
index 08bc5981b7..0000000000
--- a/modules/gui/macosx/PXSourceList.m
+++ /dev/null
@@ -1,831 +0,0 @@
-//
-// PXSourceList.m
-// PXSourceList
-//
-// Created by Alex Rozanski on 05/09/2009.
-// Copyright 2009-10 Alex Rozanski http://perspx.com
-//
-// GC-enabled code revised by Stefan Vogt http://byteproject.net
-//
-
-#import "CompatibilityFixes.h"
-#import "PXSourceList.h"
-#import "SideBarItem.h"
-
-//Layout constants
-#define MIN_BADGE_WIDTH 22.0 //The minimum badge width for each item (default 22.0)
-#define BADGE_HEIGHT 14.0 //The badge height for each item (default 14.0)
-#define BADGE_MARGIN 5.0 //The spacing between the badge and the cell for that row
-#define ROW_RIGHT_MARGIN 5.0 //The spacing between the right edge of the badge and the edge of the table column
-#define ICON_SPACING 2.0 //The spacing between the icon and it's adjacent cell
-#define DISCLOSURE_TRIANGLE_SPACE 18.0 //The indentation reserved for disclosure triangles for non-group items
-
-//Drawing constants
-#define BADGE_BACKGROUND_COLOR [NSColor colorWithCalibratedRed:(152/255.0) green:(168/255.0) blue:(202/255.0) alpha:1]
-#define BADGE_HIDDEN_BACKGROUND_COLOR [NSColor colorWithDeviceWhite:(180/255.0) alpha:1]
-#define BADGE_SELECTED_TEXT_COLOR [NSColor keyboardFocusIndicatorColor]
-#define BADGE_SELECTED_UNFOCUSED_TEXT_COLOR [NSColor colorWithCalibratedRed:(153/255.0) green:(169/255.0) blue:(203/255.0) alpha:1]
-#define BADGE_SELECTED_HIDDEN_TEXT_COLOR [NSColor colorWithCalibratedWhite:(170/255.0) alpha:1]
-#define BADGE_FONT [NSFont boldSystemFontOfSize:11]
-
-//Delegate notification constants
-NSString * const PXSLSelectionIsChangingNotification = @"PXSourceListSelectionIsChanging";
-NSString * const PXSLSelectionDidChangeNotification = @"PXSourceListSelectionDidChange";
-NSString * const PXSLItemWillExpandNotification = @"PXSourceListItemWillExpand";
-NSString * const PXSLItemDidExpandNotification = @"PXSourceListItemDidExpand";
-NSString * const PXSLItemWillCollapseNotification = @"PXSourceListItemWillCollapse";
-NSString * const PXSLItemDidCollapseNotification = @"PXSourceListItemDidCollapse";
-NSString * const PXSLDeleteKeyPressedOnRowsNotification = @"PXSourceListDeleteKeyPressedOnRows";
-
-#pragma mark -
- at interface PXSourceList ()
-
-- (NSSize)sizeOfBadgeAtRow:(NSInteger)rowIndex;
-- (void)drawBadgeForRow:(NSInteger)rowIndex inRect:(NSRect)badgeFrame;
-- (void)registerDelegateToReceiveNotification:(NSString*)notification withSelector:(SEL)selector;
-
- at end
-
-#pragma mark -
- at implementation PXSourceList
-
- at dynamic dataSource;
- at dynamic delegate;
-
-#pragma mark Init/Dealloc/Finalize
-
-- (id)initWithCoder:(NSCoder*)decoder
-{
- if(self=[super initWithCoder:decoder])
- {
- [self setDelegate:(id<PXSourceListDelegate, NSOutlineViewDelegate>)[super delegate]];
- [super setDelegate:self];
- [self setDataSource:(id<PXSourceListDataSource, NSOutlineViewDataSource>)[super dataSource]];
- [super setDataSource:self];
-
- _iconSize = NSMakeSize(16,16);
- }
-
- return self;
-}
-
-- (void)dealloc
-{
- //Unregister the delegate from receiving notifications
- [[NSNotificationCenter defaultCenter] removeObserver:_secondaryDelegate];
-}
-
-#pragma mark -
-#pragma mark Custom Accessors
-
-- (void)setDelegate:(id<PXSourceListDelegate>)aDelegate
-{
- //Unregister the old delegate from receiving notifications
- [[NSNotificationCenter defaultCenter] removeObserver:_secondaryDelegate name:nil object:self];
-
- _secondaryDelegate = aDelegate;
- //Register the new delegate to receive notifications
- [self registerDelegateToReceiveNotification:PXSLSelectionIsChangingNotification withSelector:@selector(sourceListSelectionIsChanging:)];
- [self registerDelegateToReceiveNotification:PXSLSelectionDidChangeNotification withSelector:@selector(sourceListSelectionDidChange:)];
- [self registerDelegateToReceiveNotification:PXSLItemWillExpandNotification withSelector:@selector(sourceListItemWillExpand:)];
- [self registerDelegateToReceiveNotification:PXSLItemDidExpandNotification withSelector:@selector(sourceListItemDidExpand:)];
- [self registerDelegateToReceiveNotification:PXSLItemWillCollapseNotification withSelector:@selector(sourceListItemWillCollapse:)];
- [self registerDelegateToReceiveNotification:PXSLItemDidCollapseNotification withSelector:@selector(sourceListItemDidCollapse:)];
- [self registerDelegateToReceiveNotification:PXSLDeleteKeyPressedOnRowsNotification withSelector:@selector(sourceListDeleteKeyPressedOnRows:)];
-}
-
-
-- (void)setDataSource:(id<PXSourceListDataSource>)aDataSource
-{
- _secondaryDataSource = aDataSource;
-
- if ([self respondsToSelector:@selector(reloadData)])
- [self reloadData];
-}
-
-- (void)setIconSize:(NSSize)newIconSize
-{
- _iconSize = newIconSize;
- CGFloat rowHeight = [self rowHeight];
-
- //Make sure icon height does not exceed row height; if so constrain, keeping width and height in proportion
- if(_iconSize.height>rowHeight)
- {
- _iconSize.width = _iconSize.width * (rowHeight/_iconSize.height);
- _iconSize.height = rowHeight;
- }
-}
-
-#pragma mark -
-#pragma mark Data Management
-
-- (void)reloadData
-{
- if ([super respondsToSelector:@selector(reloadData)])
- [super reloadData];
-
- //Expand items that are displayed as always expanded
- if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)] &&
- [_secondaryDelegate respondsToSelector:@selector(sourceList:isGroupAlwaysExpanded:)])
- {
- for(NSUInteger i=0;i<[self numberOfGroups];i++)
- {
- id item = [_secondaryDataSource sourceList:self child:i ofItem:nil];
-
- if([self isGroupAlwaysExpanded:item]) {
- [self expandItem:item expandChildren:NO];
- }
- }
- }
-
- //If there are selected rows and the item hierarchy has changed, make sure a Group row isn't
- //selected
- if([self numberOfSelectedRows]>0) {
- NSIndexSet *selectedIndexes = [self selectedRowIndexes];
- NSUInteger firstSelectedRow = [selectedIndexes firstIndex];
-
- //Is a group item selected?
- if([self isGroupItem:[self itemAtRow:firstSelectedRow]]) {
- //Work backwards to find the first non-group row
- BOOL foundRow = NO;
- for(NSUInteger i=firstSelectedRow;i>0;i--)
- {
- if(![self isGroupItem:[self itemAtRow:i]]) {
- [self selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];
- foundRow = YES;
- break;
- }
- }
-
- //If there is no non-group row preceding the currently selected group item, remove the selection
- //from the Source List
- if(!foundRow) {
- [self deselectAll:self];
- }
- }
- }
- else if(![self allowsEmptySelection]&&[self numberOfSelectedRows]==0)
- {
- //Select the first non-group row if no rows are selected, and empty selection is disallowed
- for(NSUInteger i=0;i<[self numberOfRows];i++)
- {
- if(![self isGroupItem:[self itemAtRow:i]]) {
- [self selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];
- break;
- }
- }
- }
-}
-
-- (NSUInteger)numberOfGroups
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:numberOfChildrenOfItem:)]) {
- return [_secondaryDataSource sourceList:self numberOfChildrenOfItem:nil];
- }
- return 0;
-}
-
-
-- (BOOL)isGroupItem:(id)item
-{
- //Groups are defined as root items (at level 0)
- return 0==[self levelForItem:item];
-}
-
-
-- (BOOL)isGroupAlwaysExpanded:(id)group
-{
- //Make sure that the item IS a group to prevent unwanted queries sent to the data source
- if([self isGroupItem:group]) {
- //Query the data source
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:isGroupAlwaysExpanded:)]) {
- return [_secondaryDelegate sourceList:self isGroupAlwaysExpanded:group];
- }
- }
-
- return NO;
-}
-
-
-- (BOOL)itemHasBadge:(id)item
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:itemHasBadge:)]) {
- return [_secondaryDataSource sourceList:self itemHasBadge:item];
- }
-
- return NO;
-}
-
-- (NSInteger)badgeValueForItem:(id)item
-{
- //Make sure that the item has a badge
- if(![self itemHasBadge:item]) {
- return NSNotFound;
- }
-
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:badgeValueForItem:)]) {
- return [_secondaryDataSource sourceList:self badgeValueForItem:item];
- }
-
- return NSNotFound;
-}
-
-#pragma mark -
-#pragma mark Selection Handling
-
-- (void)selectRowIndexes:(NSIndexSet*)indexes byExtendingSelection:(BOOL)extend
-{
- NSUInteger numberOfIndexes = [indexes count];
-
- //Prevent empty selection if we don't want it
- if(![self allowsEmptySelection]&&0==numberOfIndexes) {
- return;
- }
-
- //Would use blocks but we're also targeting 10.5...
- //Get the selected indexes
- NSUInteger *selectedIndexes = malloc(sizeof(NSUInteger)*numberOfIndexes);
- [indexes getIndexes:selectedIndexes maxCount:numberOfIndexes inIndexRange:nil];
-
- //Loop through the indexes and only add non-group row indexes
- //Allows selection across groups without selecting the group rows
- NSMutableIndexSet *newSelectionIndexes = [NSMutableIndexSet indexSet];
- for(NSInteger i=0;i<numberOfIndexes;i++)
- {
- if(![self isGroupItem:[self itemAtRow:selectedIndexes[i]]]) {
- [newSelectionIndexes addIndex:selectedIndexes[i]];
- }
- }
-
- //If there are any non-group rows selected
- if([newSelectionIndexes count]>0) {
- [super selectRowIndexes:newSelectionIndexes byExtendingSelection:extend];
- }
-
- //C memory management... *sigh*
- free(selectedIndexes);
-}
-
-#pragma mark -
-#pragma mark Layout
-
-- (NSRect)frameOfOutlineCellAtRow:(NSInteger)row
-{
- //Return a zero-rect if the item is always expanded (a disclosure triangle will not be drawn)
- if([self isGroupAlwaysExpanded:[self itemAtRow:row]]) {
- return NSZeroRect;
- }
-
- return [super frameOfOutlineCellAtRow:row];
-}
-
-
-- (NSRect)frameOfCellAtColumn:(NSInteger)column row:(NSInteger)row
-{
- id item = [self itemAtRow:row];
-
- NSCell *cell = [self preparedCellAtColumn:column row:row];
- NSSize cellSize = [cell cellSize];
- if (!([cell type] == NSImageCellType) && !([cell type] == NSTextCellType))
- cellSize = [cell cellSizeForBounds:[super frameOfCellAtColumn:column row:row]];
-
- NSRect cellFrame = [super frameOfCellAtColumn:column row:row];
- NSRect rowRect = [self rectOfRow:row];
-
- if([self isGroupItem:item])
- {
- CGFloat minX = NSMinX(cellFrame);
-
- //Set the origin x-coord; if there are no children of the group at current, there will still be a
- //margin to the left of the cell (in cellFrame), which we don't want
- if([self isGroupAlwaysExpanded:[self itemAtRow:row]]) {
- minX = 7;
- }
-
- return NSMakeRect(minX, NSMidY(cellFrame)-(cellSize.height/2.0), NSWidth(rowRect)-minX, cellSize.height);
- }
- else
- {
- CGFloat leftIndent = ([self levelForRow:row] -1)*[self indentationPerLevel]+DISCLOSURE_TRIANGLE_SPACE;
-
- //Calculate space left for a badge if need be
- CGFloat rightIndent = [self sizeOfBadgeAtRow:row].width+ROW_RIGHT_MARGIN;
-
- //Allow space for an icon if need be
- if(![self isGroupItem:item]&&[_secondaryDataSource respondsToSelector:@selector(sourceList:itemHasIcon:)])
- {
- if([_secondaryDataSource sourceList:self itemHasIcon:item]) {
- leftIndent += [self iconSize].width+(ICON_SPACING*2);
- }
- }
- return NSMakeRect(leftIndent, NSMidY(rowRect)-(cellSize.height/2.0), NSWidth(rowRect)-rightIndent-leftIndent, cellSize.height);
- }
-}
-
-
-//This method calculates and returns the size of the badge for the row index passed to the method. If the
-//row for the row index passed to the method does not have a badge, then NSZeroSize is returned.
-- (NSSize)sizeOfBadgeAtRow:(NSInteger)rowIndex
-{
- id rowItem = [self itemAtRow:rowIndex];
-
- //Make sure that the item has a badge
- if(![self itemHasBadge:rowItem]) {
- return NSZeroSize;
- }
-
- NSAttributedString *badgeAttrString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%ld", [self badgeValueForItem:rowItem]] attributes:[NSDictionary dictionaryWithObjectsAndKeys:BADGE_FONT, NSFontAttributeName, nil]];
- NSSize stringSize = [badgeAttrString size];
-
- //Calculate the width needed to display the text or the minimum width if it's smaller
- CGFloat width = stringSize.width+(2*BADGE_MARGIN);
-
- if(width<MIN_BADGE_WIDTH) {
- width = MIN_BADGE_WIDTH;
- }
-
- return NSMakeSize(width, BADGE_HEIGHT);
-}
-
-
-#pragma mark -
-#pragma mark Drawing
-
-- (void)drawRow:(NSInteger)rowIndex clipRect:(NSRect)clipRect
-{
- [super drawRow:rowIndex clipRect:clipRect];
- id item = [self itemAtRow:rowIndex];
-
- //Draw an icon if the item has one
- if(![self isGroupItem:item]&&[_secondaryDataSource respondsToSelector:@selector(sourceList:itemHasIcon:)])
- {
- if([_secondaryDataSource sourceList:self itemHasIcon:item])
- {
- NSRect cellFrame = [self frameOfCellAtColumn:0 row:rowIndex];
- NSSize iconSize = [self iconSize];
- NSRect iconRect = NSMakeRect(NSMinX(cellFrame)-iconSize.width-ICON_SPACING, NSMidY(cellFrame)-(iconSize.width/2.0f), iconSize.width, iconSize.height);
-
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:iconForItem:)])
- {
- NSImage *icon = [_secondaryDataSource sourceList:self iconForItem:item];
- if(icon!=nil)
- {
- NSSize actualIconSize = [icon size];
- //If the icon is *smaller* than the size retrieved from the -iconSize property, make sure we
- //reduce the size of the rectangle to draw the icon in, so that it is not stretched.
- if((actualIconSize.width<iconSize.width)||(actualIconSize.height<iconSize.height))
- {
- iconRect = NSMakeRect(NSMidX(iconRect)-(actualIconSize.width/2.0f), NSMidY(iconRect)-(actualIconSize.height/2.0f), actualIconSize.width, actualIconSize.height);
- }
-
- [icon drawInRect:iconRect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1
- respectFlipped:YES hints:nil];
- }
- }
- }
- }
-
- //Draw the badge if the item has one
- if([self itemHasBadge:item])
- {
- NSRect rowRect = [self rectOfRow:rowIndex];
- NSSize badgeSize = [self sizeOfBadgeAtRow:rowIndex];
-
- NSRect badgeFrame = NSMakeRect(NSMaxX(rowRect)-badgeSize.width-ROW_RIGHT_MARGIN,
- NSMidY(rowRect)-(badgeSize.height/2.0),
- badgeSize.width,
- badgeSize.height);
- [self drawBadgeForRow:rowIndex inRect:badgeFrame];
- }
-}
-
-- (void)drawBadgeForRow:(NSInteger)rowIndex inRect:(NSRect)badgeFrame
-{
- id rowItem = [self itemAtRow:rowIndex];
- NSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeFrame
- xRadius:(BADGE_HEIGHT/2.0)
- yRadius:(BADGE_HEIGHT/2.0)];
-
- //Get window and control state to determine colours used
- BOOL isVisible = [[NSApp mainWindow] isVisible];
- BOOL isFocused = [[[self window] firstResponder] isEqual:self];
- NSInteger rowBeingEdited = [self editedRow];
-
- //Set the attributes based on the row state
- NSDictionary *attributes;
- NSColor *backgroundColor;
-
- if([[self selectedRowIndexes] containsIndex:rowIndex])
- {
- backgroundColor = [NSColor whiteColor];
- //Set the text color based on window and control state
- NSColor *textColor;
- if(isVisible && (isFocused || rowBeingEdited==rowIndex)) {
- textColor = BADGE_SELECTED_TEXT_COLOR;
- }
- else if(isVisible && !isFocused) {
- textColor = BADGE_SELECTED_UNFOCUSED_TEXT_COLOR;
- }
- else {
- textColor = BADGE_SELECTED_HIDDEN_TEXT_COLOR;
- }
-
- attributes = [[NSDictionary alloc] initWithObjectsAndKeys:BADGE_FONT, NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil];
- }
- else
- {
- //Set the text colour based on window and control state
- NSColor *badgeColor = [NSColor whiteColor];
-
- if(isVisible) {
- //If the data source returns a custom colour..
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:badgeBackgroundColorForItem:)]) {
- backgroundColor = [_secondaryDataSource sourceList:self badgeBackgroundColorForItem:rowItem];
-
- if(backgroundColor==nil)
- backgroundColor = BADGE_BACKGROUND_COLOR;
- }
- else { //Otherwise use the default (purple-blue colour)
- backgroundColor = BADGE_BACKGROUND_COLOR;
- }
-
- //If the delegate wants a custom badge text colour..
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:badgeTextColorForItem:)]) {
- badgeColor = [_secondaryDataSource sourceList:self badgeTextColorForItem:rowItem];
-
- if(badgeColor==nil)
- badgeColor = [NSColor whiteColor];
- }
- }
- else { //Gray colour
- backgroundColor = BADGE_HIDDEN_BACKGROUND_COLOR;
- }
- attributes = [[NSDictionary alloc] initWithObjectsAndKeys:BADGE_FONT, NSFontAttributeName, badgeColor, NSForegroundColorAttributeName, nil];
- }
-
- [backgroundColor set];
- [badgePath fill];
-
- //Draw the badge text
- NSAttributedString *badgeAttrString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%ld", [self badgeValueForItem:rowItem]] attributes:attributes];
-
- NSSize stringSize = [badgeAttrString size];
- NSPoint badgeTextPoint = NSMakePoint(NSMidX(badgeFrame)-(stringSize.width/2.0), //Center in the badge frame
- NSMidY(badgeFrame)-(stringSize.height/2.0)); //Center in the badge frame
- [badgeAttrString drawAtPoint:badgeTextPoint];
-}
-
-#pragma mark -
-#pragma mark Keyboard Handling
-
-- (void)keyDown:(NSEvent *)theEvent
-{
- NSIndexSet *selectedIndexes = [self selectedRowIndexes];
- NSString *keyCharacters = [theEvent characters];
-
- //Make sure we have a selection
- if([selectedIndexes count]>0)
- {
- if([keyCharacters length]>0)
- {
- unichar firstKey = [keyCharacters characterAtIndex:0];
- if(firstKey==NSUpArrowFunctionKey||firstKey==NSDownArrowFunctionKey)
- {
- //Handle keyboard navigation across groups
- if([selectedIndexes count]==1&&!([theEvent modifierFlags] & NSShiftKeyMask))
- {
- int delta = firstKey==NSDownArrowFunctionKey?1:-1;
- //Search "backwards" if up arrow, "forwards" if down
-
- NSInteger newRow = [selectedIndexes firstIndex];
- //Keep incrementing/decrementing the row until a non-header row is reached
- do {
- newRow+=delta;
-
- //If out of bounds of the number of rows..
- if(newRow<0||newRow==[self numberOfRows])
- break;
- } while([self isGroupItem:[self itemAtRow:newRow]]);
-
- [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
-
- return;
- }
- }
- else if(firstKey==NSDeleteCharacter||firstKey==NSBackspaceCharacter)
- {
- //Post the notification
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLDeleteKeyPressedOnRowsNotification object:self userInfo:[NSDictionary dictionaryWithObject:selectedIndexes forKey:@"rows"]];
-
- return;
-
- }
-
- }
-
- }
-
- //We don't care about it
- [super keyDown:theEvent];
-}
-
-#pragma mark -
-#pragma mark Menu Handling
-
-
-- (NSMenu *)menuForEvent:(NSEvent *)theEvent
-{
- NSMenu * m = nil;
-
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:menuForEvent:item:)]) {
- NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
- NSInteger row = [self rowAtPoint:clickPoint];
- id clickedItem = [self itemAtRow:row];
-
- if ([clickedItem sdtype] > 0)
- m = [_secondaryDelegate sourceList:self menuForEvent:theEvent item:clickedItem];
- else
- m = [super menuForEvent:theEvent];
- }
-
- if (m == nil) {
- m = [super menuForEvent:theEvent];
- }
-
- return m;
-}
-
-#pragma mark -
-#pragma mark NSOutlineView Data Source methods
-
-- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
-{
- if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
- return [_secondaryDataSource sourceList:self numberOfChildrenOfItem:item];
- }
-
- return 0;
-}
-
-
-- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
-{
- if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
- return [_secondaryDataSource sourceList:self child:index ofItem:item];
- }
-
- return nil;
-}
-
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
-{
- if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
- return [_secondaryDataSource sourceList:self isItemExpandable:item];
- }
-
- return NO;
-}
-
-
-- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
-{
- if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
- return [_secondaryDataSource sourceList:self objectValueForItem:item];
- }
-
- return nil;
-}
-
-
-- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
-{
- if([_secondaryDataSource conformsToProtocol:@protocol(PXSourceListDataSource)]) {
- [_secondaryDataSource sourceList:self setObjectValue:object forItem:item];
- }
-}
-
-
-- (id)outlineView:(NSOutlineView *)outlineView itemForPersistentObject:(id)object
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:itemForPersistentObject:)]) {
- return [_secondaryDataSource sourceList:self itemForPersistentObject:object];
- }
-
- return nil;
-}
-
-- (id)outlineView:(NSOutlineView *)outlineView persistentObjectForItem:(id)item
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:persistentObjectForItem:)]) {
- return [_secondaryDataSource sourceList:self persistentObjectForItem:item];
- }
-
- return nil;
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:writeItems:toPasteboard:)]) {
- return [_secondaryDataSource sourceList:self writeItems:items toPasteboard:pasteboard];
- }
-
- return NO;
-}
-
-- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:validateDrop:proposedItem:proposedChildIndex:)]) {
- return [_secondaryDataSource sourceList:self validateDrop:info proposedItem:item proposedChildIndex:index];
- }
-
- return NSDragOperationNone;
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:acceptDrop:item:childIndex:)]) {
- return [_secondaryDataSource sourceList:self acceptDrop:info item:item childIndex:index];
- }
-
- return NO;
-}
-- (NSArray *)outlineView:(NSOutlineView *)outlineView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedItems:(NSArray *)items
-{
- if([_secondaryDataSource respondsToSelector:@selector(sourceList:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:)]) {
- return [_secondaryDataSource sourceList:self namesOfPromisedFilesDroppedAtDestination:dropDestination forDraggedItems:items];
- }
-
- return nil;
-}
-
-
-#pragma mark -
-#pragma mark NSOutlineView Delegate methods
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item
-{
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldExpandItem:)]) {
- return [_secondaryDelegate sourceList:self shouldExpandItem:item];
- }
-
- return YES;
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item
-{
- //Make sure the item isn't displayed as always expanded
- if([self isGroupItem:item])
- {
- if([self isGroupAlwaysExpanded:item]) {
- return NO;
- }
- }
-
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldCollapseItem:)]) {
- return [_secondaryDelegate sourceList:self shouldCollapseItem:item];
- }
-
- return YES;
-}
-
-- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
-{
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:dataCellForItem:)]) {
- return [_secondaryDelegate sourceList:self dataCellForItem:item];
- }
-
- NSInteger row = [self rowForItem:item];
-
- //Return the default table column
- return [[[self tableColumns] firstObject] dataCellForRow:row];
-}
-
-- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
-{
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:willDisplayCell:forItem:)]) {
- [_secondaryDelegate sourceList:self willDisplayCell:cell forItem:item];
- }
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
-{
- //Make sure that the item isn't a group as they can't be selected
- if(![self isGroupItem:item]) {
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldSelectItem:)]) {
- return [_secondaryDelegate sourceList:self shouldSelectItem:item];
- }
- }
- else {
- return NO;
- }
-
- return YES;
-}
-
-
-- (NSIndexSet *)outlineView:(NSOutlineView *)outlineView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
-{
- //The outline view will try to select the first row if -[allowsEmptySelection:] is set to NO – if this is a group row
- //stop it from doing so and leave it to our implementation of-[reloadData] which will select the first non-group row
- //for us.
- if([self numberOfSelectedRows]==0) {
- if([self isGroupItem:[self itemAtRow:[proposedSelectionIndexes firstIndex]]]) {
- return [NSIndexSet indexSet];
- }
- }
-
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:selectionIndexesForProposedSelection:)]) {
- return [_secondaryDelegate sourceList:self selectionIndexesForProposedSelection:proposedSelectionIndexes];
- }
-
- //Since we implement this method, something must be returned to the outline view
- return proposedSelectionIndexes;
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
-{
- //Group titles can't be edited
- if([self isGroupItem:item])
- return NO;
-
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldEditItem:)]) {
- return [_secondaryDelegate sourceList:self shouldEditItem:item];
- }
-
- return YES;
-}
-
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
-{
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:shouldTrackCell:forItem:)]) {
- return [_secondaryDelegate sourceList:self shouldTrackCell:cell forItem:item];
- }
-
- return NO;
-}
-
-- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
-{
- if([_secondaryDelegate respondsToSelector:@selector(sourceList:heightOfRowByItem:)]) {
- return [_secondaryDelegate sourceList:self heightOfRowByItem:item];
- }
-
- return [self rowHeight];
-}
-
-- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
-{
- return [self isGroupItem:item];
-}
-
-#pragma mark -
-#pragma mark Notification handling
-
-/* Notification wrappers */
-- (void)outlineViewSelectionIsChanging:(NSNotification *)notification
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLSelectionIsChangingNotification object:self];
-}
-
-
-- (void)outlineViewSelectionDidChange:(NSNotification *)notification
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLSelectionDidChangeNotification object:self];
-}
-
-- (void)outlineViewItemWillExpand:(NSNotification *)notification
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemWillExpandNotification object:self userInfo:[notification userInfo]];
-}
-
-- (void)outlineViewItemDidExpand:(NSNotification *)notification
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemDidExpandNotification object:self userInfo:[notification userInfo]];
-}
-
-- (void)outlineViewItemWillCollapse:(NSNotification *)notification
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemWillCollapseNotification object:self userInfo:[notification userInfo]];
-}
-
-- (void)outlineViewItemDidCollapse:(NSNotification *)notification
-{
- [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemDidCollapseNotification object:self userInfo:[notification userInfo]];
-}
-
-- (void)registerDelegateToReceiveNotification:(NSString*)notification withSelector:(SEL)selector
-{
- NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
-
- //Set the delegate as a receiver of the notification if it implements the notification method
- if([_secondaryDelegate respondsToSelector:selector]) {
- [defaultCenter addObserver:_secondaryDelegate selector:selector name:notification object:self];
- }
-}
-
- at end
diff --git a/modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.h b/modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.h
new file mode 100755
index 0000000000..3ea5605058
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.h
@@ -0,0 +1,21 @@
+//
+// PXSourceListDelegateDataSourceProxy.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 25/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Foundation/Foundation.h>
+#import "../PXSourceList.h"
+
+ at interface PXSourceListDelegateDataSourceProxy : NSProxy <NSOutlineViewDelegate, NSOutlineViewDataSource, PXSourceListDelegate, PXSourceListDataSource>
+
+ at property (weak, nonatomic) PXSourceList *sourceList;
+ at property (unsafe_unretained, nonatomic) id <PXSourceListDelegate> delegate;
+ at property (unsafe_unretained, nonatomic) id <PXSourceListDataSource> dataSource;
+
+- (id)initWithSourceList:(PXSourceList *)sourceList;
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.m b/modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.m
new file mode 100755
index 0000000000..c5e2e8e286
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/Internal/PXSourceListDelegateDataSourceProxy.m
@@ -0,0 +1,470 @@
+//
+// PXSourceListDelegateDataSourceProxy.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 25/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceListDelegateDataSourceProxy.h"
+
+#import <objc/runtime.h>
+#import "PXSourceListPrivateConstants.h"
+#import "PXSourceListRuntimeAdditions.h"
+
+// Internal constants.
+static NSString * const forwardingMapForwardingMethodNameKey = @"methodName";
+static NSString * const forwardingMapForwardedArgumentIndexesKey = @"forwardedArgumentIndexes";
+
+static NSArray * __outlineViewDelegateMethods = nil;
+static NSArray * __outlineViewDataSourceMethods = nil;
+static NSArray * __requiredOutlineViewDataSourceMethods = nil;
+
+// Cache the PXSourceListDelegate and PXSourceListDataSource method names so that if these methods are invoked on
+// us, we can quickly forward them to the delegate and dataSource using -forwardingTargetForSelector: without going
+// through -forwardInvocation:.
+static NSArray * __fastPathForwardingDelegateMethods = nil;
+static NSArray * __fastPathForwardingDataSourceMethods = nil;
+
+// We want to suppress the warnings for protocol methods not being implemented. As a proxy we will forward these
+// messages to the actual delegate and data source.
+#pragma clang diagnostic ignored "-Wprotocol"
+ at implementation PXSourceListDelegateDataSourceProxy
+
++ (void)initialize
+{
+ __outlineViewDelegateMethods = px_methodNamesForProtocol(@protocol(NSOutlineViewDelegate));
+ __outlineViewDataSourceMethods = px_methodNamesForProtocol(@protocol(NSOutlineViewDataSource));
+ __fastPathForwardingDelegateMethods = [self fastPathForwardingDelegateMethods];
+ __fastPathForwardingDataSourceMethods = px_methodNamesForProtocol(@protocol(PXSourceListDataSource));
+
+ __requiredOutlineViewDataSourceMethods = @[NSStringFromSelector(@selector(outlineView:numberOfChildrenOfItem:)),
+ NSStringFromSelector(@selector(outlineView:child:ofItem:)),
+ NSStringFromSelector(@selector(outlineView:isItemExpandable:)),
+ NSStringFromSelector(@selector(outlineView:objectValueForTableColumn:byItem:))];
+
+ // Add the custom mappings first before we add the 'regular' mappings.
+ [self addCustomMethodNameMappings];
+
+ // Now add the 'regular' mappings.
+ [self addEntriesToMethodForwardingMap:[self methodNameMappingsForProtocol:@protocol(NSOutlineViewDelegate)]];
+ [self addEntriesToMethodForwardingMap:[self methodNameMappingsForProtocol:@protocol(NSOutlineViewDataSource)]];
+}
+
+- (id)initWithSourceList:(PXSourceList *)sourceList
+{
+ _sourceList = sourceList;
+
+ return self;
+}
+
+- (void)dealloc
+{
+ //Unregister the delegate from receiving notifications
+ [[NSNotificationCenter defaultCenter] removeObserver:self.delegate name:nil object:self.sourceList];
+}
+
+#pragma mark - Accessors
+
+- (void)setDelegate:(id<PXSourceListDelegate>)delegate
+{
+ if (self.delegate)
+ [[NSNotificationCenter defaultCenter] removeObserver:self.delegate name:nil object:self.sourceList];
+
+ _delegate = delegate;
+
+ //Register the new delegate to receive notifications
+ [self registerDelegateToReceiveNotification:PXSLSelectionIsChangingNotification
+ withSelector:@selector(sourceListSelectionIsChanging:)];
+ [self registerDelegateToReceiveNotification:PXSLSelectionDidChangeNotification
+ withSelector:@selector(sourceListSelectionDidChange:)];
+ [self registerDelegateToReceiveNotification:PXSLItemWillExpandNotification
+ withSelector:@selector(sourceListItemWillExpand:)];
+ [self registerDelegateToReceiveNotification:PXSLItemDidExpandNotification
+ withSelector:@selector(sourceListItemDidExpand:)];
+ [self registerDelegateToReceiveNotification:PXSLItemWillCollapseNotification
+ withSelector:@selector(sourceListItemWillCollapse:)];
+ [self registerDelegateToReceiveNotification:PXSLItemDidCollapseNotification
+ withSelector:@selector(sourceListItemDidCollapse:)];
+ [self registerDelegateToReceiveNotification:PXSLDeleteKeyPressedOnRowsNotification
+ withSelector:@selector(sourceListDeleteKeyPressedOnRows:)];
+}
+
+- (void)setDataSource:(id<PXSourceListDataSource>)dataSource
+{
+ _dataSource = dataSource;
+}
+
+#pragma mark - NSObject Overrides
+
+- (BOOL)respondsToSelector:(SEL)aSelector
+{
+ NSString *methodName = NSStringFromSelector(aSelector);
+
+ // Only let the source list override NSOutlineView delegate and data source methods.
+ if ([self.sourceList respondsToSelector:aSelector] && ([__outlineViewDataSourceMethods containsObject:methodName] || [__outlineViewDelegateMethods containsObject:methodName]))
+ return YES;
+
+ if ([__requiredOutlineViewDataSourceMethods containsObject:methodName])
+ return YES;
+
+ if ([__fastPathForwardingDelegateMethods containsObject:methodName])
+ return [self.delegate respondsToSelector:aSelector];
+ if ([__fastPathForwardingDataSourceMethods containsObject:methodName])
+ return [self.dataSource respondsToSelector:aSelector];
+
+ id forwardingObject = [self forwardingObjectForSelector:aSelector];
+ NSDictionary *forwardingInformation = [[self class] forwardingInformationForSelector:aSelector];
+
+ if(!forwardingObject || !forwardingInformation)
+ return NO;
+
+ return [forwardingObject respondsToSelector:NSSelectorFromString([forwardingInformation objectForKey:forwardingMapForwardingMethodNameKey])];
+}
+
+- (BOOL)conformsToProtocol:(Protocol *)protocol
+{
+ return class_conformsToProtocol(object_getClass(self), protocol);
+}
+
+// Fast-path delegate and data source methods aren't handled here; they are taken care of in -forwardingTargetForSelector:.
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
+{
+ NSString *methodName = NSStringFromSelector(aSelector);
+
+ struct objc_method_description description = {NULL, NULL};
+
+ if ([__outlineViewDelegateMethods containsObject:methodName])
+ description = px_methodDescriptionForProtocolMethod(@protocol(NSOutlineViewDelegate), aSelector);
+ else if ([__outlineViewDataSourceMethods containsObject:methodName])
+ description = px_methodDescriptionForProtocolMethod(@protocol(NSOutlineViewDataSource), aSelector);
+
+ if (description.name == NULL && description.types == NULL)
+ return nil;
+
+ return [NSMethodSignature signatureWithObjCTypes:description.types];
+}
+
+- (BOOL) isKindOfClass:(Class)aClass
+{
+ return NO;
+}
+
+- (void)forwardInvocation:(NSInvocation *)anInvocation
+{
+ SEL sourceSelector = anInvocation.selector;
+
+ // Give the Source List a chance to handle the selector first (this is a bit of a hack for the time being
+ // and should be changed).
+ if ([self.sourceList respondsToSelector:sourceSelector]) {
+ [anInvocation invokeWithTarget:self.sourceList];
+ return;
+ }
+
+ id forwardingObject = [self forwardingObjectForSelector:sourceSelector];
+ NSDictionary *forwardingInformation = [[self class] forwardingInformationForSelector:sourceSelector];
+
+ if(!forwardingObject || !forwardingInformation) {
+ [super forwardInvocation:anInvocation];
+ return;
+ }
+
+ SEL forwardingSelector = NSSelectorFromString([forwardingInformation objectForKey:forwardingMapForwardingMethodNameKey]);
+
+ NSArray *forwardedArgumentIndexes = [forwardingInformation objectForKey:forwardingMapForwardedArgumentIndexesKey];
+ anInvocation.selector = forwardingSelector;
+
+ NSMethodSignature *methodSignature = [forwardingObject methodSignatureForSelector:forwardingSelector];
+
+ /* Catch the case where we have advertised ourselves as responding to a selector required by NSOutlineView
+ for a valid dataSource but the corresponding PXSourceListDataSource method isn't implemented by the dataSource.
+ */
+ if ([__requiredOutlineViewDataSourceMethods containsObject:NSStringFromSelector(sourceSelector)]
+ && ![self.dataSource respondsToSelector:forwardingSelector]) {
+ return;
+ }
+
+ /* Modify the arguments in the invocation if the source and target selector arguments are different.
+
+ The forwardedArgumentIndexes array contains the indexes of arguments in the original invocation that we want
+ to use in our modified invocation. E.g. @[@0, @2] means take the first and third arguments and only use them
+ when forwarding. We want to do this when the forwarded selector has a different number of arguments to the
+ source selector (see +addCustomMethodNameMappings).
+
+ Note that this implementation only works if the arguments in `forwardedArgumentIndexes` are monotonically
+ increasing (which is good enough for now).
+
+ */
+ if (forwardedArgumentIndexes) {
+ // self and _cmd are arguments 0 and 1.
+ NSUInteger invocationArgumentIndex = 2;
+ for (NSNumber *newArgumentIndex in forwardedArgumentIndexes) {
+ NSInteger forwardedArgumentIndex = newArgumentIndex.integerValue;
+
+ // Handle the case where we want to use (for example) the third argument from the original invocation
+ // as the second argument of our modified invocation.
+ if (invocationArgumentIndex != forwardedArgumentIndex) {
+ NSUInteger argumentSize = 0;
+ NSGetSizeAndAlignment([methodSignature getArgumentTypeAtIndex:invocationArgumentIndex], &argumentSize, NULL);
+
+ void *argument = malloc(argumentSize);
+ [anInvocation getArgument:argument atIndex:forwardedArgumentIndex + 2]; // Take self and _cmd into account again.
+ [anInvocation setArgument:argument atIndex:invocationArgumentIndex];
+ free(argument);
+ }
+
+ invocationArgumentIndex++;
+ }
+ }
+
+ [anInvocation invokeWithTarget:forwardingObject];
+}
+
+- (id)forwardingTargetForSelector:(SEL)aSelector
+{
+ NSString *methodName = NSStringFromSelector(aSelector);
+
+ if ([__fastPathForwardingDelegateMethods containsObject:methodName])
+ return self.delegate;
+
+ if ([__fastPathForwardingDataSourceMethods containsObject:methodName])
+ return self.dataSource;
+
+ return nil;
+}
+
+#pragma mark - Method Forwarding
+
++ (NSMutableDictionary *)methodForwardingMap
+{
+ static NSMutableDictionary *_methodForwardingMap = nil;
+ if (!_methodForwardingMap)
+ _methodForwardingMap = [[NSMutableDictionary alloc] init];
+
+ return _methodForwardingMap;
+}
+
++ (void)addEntriesToMethodForwardingMap:(NSDictionary *)entries
+{
+ NSArray *methodForwardingBlacklist = [self methodForwardingBlacklist];
+ NSMutableDictionary *methodForwardingMap = [self methodForwardingMap];
+
+ for (NSString *key in entries) {
+ if (![methodForwardingBlacklist containsObject:key] && ![methodForwardingMap objectForKey:key])
+ [methodForwardingMap setObject:[entries objectForKey:key] forKey:key];
+ }
+}
+
++ (NSDictionary *)methodNameMappingsForProtocol:(Protocol *)protocol
+{
+ NSMutableDictionary *methodNameMappings = [[NSMutableDictionary alloc] init];
+ NSArray *protocolMethods = px_allProtocolMethods(protocol);
+ NSString *protocolName = NSStringFromProtocol(protocol);
+
+ for (NSDictionary *methodInfo in protocolMethods) {
+ NSString *methodName = [methodInfo objectForKey:px_protocolMethodNameKey];
+ NSString *mappedMethodName = [self mappedMethodNameForMethodName:methodName];
+ if (!mappedMethodName) {
+ NSLog(@"PXSourceList: couldn't map method %@ from %@", methodName, protocolName);
+ continue;
+ }
+
+ [methodNameMappings setObject:@{forwardingMapForwardingMethodNameKey: mappedMethodName}
+ forKey:methodName];
+ }
+
+ return methodNameMappings;
+}
+
++ (NSString *)mappedMethodNameForMethodName:(NSString *)methodName
+{
+ NSString *outlineViewSearchString = @"outlineView";
+ NSUInteger letterVOffset = [outlineViewSearchString rangeOfString:@"V"].location;
+ NSCharacterSet *uppercaseLetterCharacterSet = [NSCharacterSet uppercaseLetterCharacterSet];
+
+ NSRange outlineViewStringRange = [methodName rangeOfString:outlineViewSearchString options:NSCaseInsensitiveSearch];
+
+ // If for some reason we can't map the method name, try to fail gracefully.
+ if (outlineViewStringRange.location == NSNotFound)
+ return nil;
+
+ BOOL isOCapitalized = [uppercaseLetterCharacterSet characterIsMember:[methodName characterAtIndex:outlineViewStringRange.location]];
+ BOOL isVCapitalized = [uppercaseLetterCharacterSet characterIsMember:[methodName characterAtIndex:outlineViewStringRange.location + letterVOffset]];
+ return [methodName stringByReplacingCharactersInRange:outlineViewStringRange
+ withString:[NSString stringWithFormat:@"%@ource%@ist", isOCapitalized ? @"S" : @"s", isVCapitalized ? @"L" : @"l"]];
+
+}
+
+- (id)forwardingObjectForSelector:(SEL)selector
+{
+ if ([__outlineViewDataSourceMethods containsObject:NSStringFromSelector(selector)])
+ return self.dataSource;
+
+ if ([__outlineViewDelegateMethods containsObject:NSStringFromSelector(selector)])
+ return self.delegate;
+
+ return nil;
+}
+
++ (NSDictionary *)forwardingInformationForSelector:(SEL)selector
+{
+ return [[self methodForwardingMap] objectForKey:NSStringFromSelector(selector)];
+}
+
+// These methods won't have mappings created for them.
++ (NSArray *)methodForwardingBlacklist
+{
+ return @[NSStringFromSelector(@selector(outlineView:shouldSelectTableColumn:)),
+ NSStringFromSelector(@selector(outlineView:shouldReorderColumn:toColumn:)),
+ NSStringFromSelector(@selector(outlineView:mouseDownInHeaderOfTableColumn:)),
+ NSStringFromSelector(@selector(outlineView:didClickTableColumn:)),
+ NSStringFromSelector(@selector(outlineView:didDragTableColumn:)),
+ NSStringFromSelector(@selector(outlineView:sizeToFitWidthOfColumn:)),
+ NSStringFromSelector(@selector(outlineView:shouldReorderColumn:toColumn:)),
+ NSStringFromSelector(@selector(outlineViewColumnDidMove:)),
+ NSStringFromSelector(@selector(outlineViewColumnDidResize:)),
+ NSStringFromSelector(@selector(outlineView:isGroupItem:))];
+}
+
+/* Add custom mappings for method names which can't have "outlineView" simply replaced with "sourceList".
+
+ For example, -outlineView:objectValueForTableColumn:byItem: should be forwarded to -sourceList:objectValueForItem:. We also only want to
+ forward the 1st and 3rd arguments when invoking this second selector.
+
+ */
++ (void)addCustomMethodNameMappings
+{
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:objectValueForTableColumn:byItem:)
+ toSelector:@selector(sourceList:objectValueForItem:)
+ forwardedArgumentIndexes:@[@0, @2]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:setObjectValue:forTableColumn:byItem:)
+ toSelector:@selector(sourceList:setObjectValue:forItem:)
+ forwardedArgumentIndexes:@[@0, @1, @3]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:viewForTableColumn:item:)
+ toSelector:@selector(sourceList:viewForItem:)
+ forwardedArgumentIndexes:@[@0, @2]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:willDisplayCell:forTableColumn:item:)
+ toSelector:@selector(sourceList:willDisplayCell:forItem:)
+ forwardedArgumentIndexes:@[@0, @1, @3]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:shouldEditTableColumn:item:)
+ toSelector:@selector(sourceList:shouldEditItem:)
+ forwardedArgumentIndexes:@[@0, @2]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:)
+ toSelector:@selector(sourceList:toolTipForCell:rect:item:mouseLocation:)
+ forwardedArgumentIndexes:@[@0, @1, @2, @4, @5]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:typeSelectStringForTableColumn:item:)
+ toSelector:@selector(sourceList:typeSelectStringForItem:)
+ forwardedArgumentIndexes:@[@0, @2]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:shouldShowCellExpansionForTableColumn:item:)
+ toSelector:@selector(sourceList:shouldShowCellExpansionForItem:)
+ forwardedArgumentIndexes:@[@0, @2]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:shouldTrackCell:forTableColumn:item:)
+ toSelector:@selector(sourceList:shouldTrackCell:forItem:)
+ forwardedArgumentIndexes:@[@0, @1, @3]];
+ [self addCustomMethodNameMappingFromSelector:@selector(outlineView:dataCellForTableColumn:item:)
+ toSelector:@selector(sourceList:dataCellForItem:)
+ forwardedArgumentIndexes:@[@0, @2]];
+}
+
++ (void)addCustomMethodNameMappingFromSelector:(SEL)fromSelector toSelector:(SEL)toSelector forwardedArgumentIndexes:(NSArray *)argumentIndexes
+{
+ [[self methodForwardingMap] setObject:@{forwardingMapForwardingMethodNameKey: NSStringFromSelector(toSelector),
+ forwardingMapForwardedArgumentIndexesKey: argumentIndexes}
+ forKey:NSStringFromSelector(fromSelector)];
+}
+
+- (BOOL)getForwardingObject:(id*)outObject andForwardingSelector:(SEL*)outSelector forSelector:(SEL)selector
+{
+ NSDictionary *methodForwardingMap = [[self class] methodForwardingMap];
+ NSString *originalMethodName = NSStringFromSelector(selector);
+ NSDictionary *forwardingInfo = [methodForwardingMap objectForKey:originalMethodName];
+ if (!forwardingInfo)
+ return NO;
+
+ id forwardingObject;
+ if ([__outlineViewDelegateMethods containsObject:originalMethodName])
+ forwardingObject = self.delegate;
+ else if ([__outlineViewDataSourceMethods containsObject:originalMethodName])
+ forwardingObject = self.dataSource;
+
+ if (!forwardingObject)
+ return NO;
+
+ if (outObject)
+ *outObject = forwardingObject;
+
+ if (outSelector)
+ *outSelector = NSSelectorFromString([forwardingInfo objectForKey:forwardingMapForwardingMethodNameKey]);
+
+ return YES;
+}
+
++ (NSArray *)fastPathForwardingDelegateMethods
+{
+ NSMutableArray *methods = [px_methodNamesForProtocol(@protocol(PXSourceListDelegate)) mutableCopy];
+
+ // Add the NSControl delegate methods manually (unfortunately these aren't part of a formal protocol).
+ [methods addObject:px_methodNameForSelector(@selector(controlTextDidEndEditing:))];
+ [methods addObject:px_methodNameForSelector(@selector(controlTextDidBeginEditing:))];
+ [methods addObject:px_methodNameForSelector(@selector(controlTextDidChange:))];
+
+ return methods;
+}
+
+#pragma mark - Notifications
+
+- (void)registerDelegateToReceiveNotification:(NSString*)notification withSelector:(SEL)selector
+{
+ NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
+
+ //Set the delegate as a receiver of the notification if it implements the notification method
+ if([self.delegate respondsToSelector:selector]) {
+ [defaultCenter addObserver:self.delegate
+ selector:selector
+ name:notification
+ object:self.sourceList];
+ }
+}
+
+/* Notification wrappers */
+- (void)outlineViewSelectionIsChanging:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLSelectionIsChangingNotification object:self.sourceList];
+}
+
+
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLSelectionDidChangeNotification object:self.sourceList];
+}
+
+- (void)outlineViewItemWillExpand:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemWillExpandNotification
+ object:self.sourceList
+ userInfo:[notification userInfo]];
+}
+
+- (void)outlineViewItemDidExpand:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemDidExpandNotification
+ object:self.sourceList
+ userInfo:[notification userInfo]];
+}
+
+- (void)outlineViewItemWillCollapse:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemWillCollapseNotification
+ object:self.sourceList
+ userInfo:[notification userInfo]];
+}
+
+- (void)outlineViewItemDidCollapse:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLItemDidCollapseNotification
+ object:self.sourceList
+ userInfo:[notification userInfo]];
+}
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/Internal/PXSourceListPrivateConstants.h b/modules/gui/macosx/PXSourceList/Internal/PXSourceListPrivateConstants.h
new file mode 100755
index 0000000000..1860126632
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/Internal/PXSourceListPrivateConstants.h
@@ -0,0 +1,18 @@
+//
+// PXSourceListPrivateConstants.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 25/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Foundation/Foundation.h>
+
+extern NSString * const PXSLSelectionIsChangingNotification;
+extern NSString * const PXSLSelectionDidChangeNotification;
+extern NSString * const PXSLItemWillExpandNotification;
+extern NSString * const PXSLItemDidExpandNotification;
+extern NSString * const PXSLItemWillCollapseNotification;
+extern NSString * const PXSLItemDidCollapseNotification;
+extern NSString * const PXSLDeleteKeyPressedOnRowsNotification;
diff --git a/modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.h b/modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.h
new file mode 100755
index 0000000000..11b40d17b2
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.h
@@ -0,0 +1,21 @@
+//
+// PXSourceListRuntimeAdditions.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 25/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+extern NSString * const px_protocolMethodNameKey;
+extern NSString * const px_protocolMethodArgumentTypesKey;
+extern NSString * const px_protocolIsRequiredMethodKey;
+
+NSArray *px_allProtocolMethods(Protocol *protocol);
+NSArray *px_methodNamesForProtocol(Protocol *protocol);
+id px_methodNameForSelector(SEL selector);
+
+struct objc_method_description px_methodDescriptionForProtocolMethod(Protocol *protocol, SEL selector);
\ No newline at end of file
diff --git a/modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.m b/modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.m
new file mode 100755
index 0000000000..69fc60ade3
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/Internal/PXSourceListRuntimeAdditions.m
@@ -0,0 +1,67 @@
+//
+// PXSourceListRuntimeAdditions.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 25/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceListRuntimeAdditions.h"
+
+NSString * const px_protocolMethodNameKey = @"methodName";
+NSString * const px_protocolMethodArgumentTypesKey = @"types";
+NSString * const px_protocolIsRequiredMethodKey = @"isRequired";
+
+NSArray *px_allProtocolMethods(Protocol *protocol)
+{
+ NSMutableArray *methodList = [[NSMutableArray alloc] init];
+
+ // We have 4 permutations as protocol_copyMethodDescriptionList() takes two BOOL arguments for the types of methods to return.
+ for (NSUInteger i = 0; i < 4; ++i) {
+ BOOL isRequiredMethod = (i / 2) % 2;
+
+ unsigned int numberOfMethodDescriptions = 0;
+ struct objc_method_description *methodDescriptions = protocol_copyMethodDescriptionList(protocol, isRequiredMethod, i % 2, &numberOfMethodDescriptions);
+
+ for (unsigned int j = 0; j < numberOfMethodDescriptions; ++j) {
+ struct objc_method_description methodDescription = methodDescriptions[j];
+ [methodList addObject:@{px_protocolMethodNameKey: px_methodNameForSelector(methodDescription.name),
+ px_protocolMethodArgumentTypesKey: [NSString stringWithUTF8String:methodDescription.types],
+ px_protocolIsRequiredMethodKey: @(isRequiredMethod)}];
+ }
+
+ free(methodDescriptions);
+ }
+
+ return methodList;
+}
+
+NSArray *px_methodNamesForProtocol(Protocol *protocol)
+{
+ NSMutableArray *methodNames = [[NSMutableArray alloc] init];
+
+ for (NSDictionary *methodInfo in px_allProtocolMethods(protocol))
+ [methodNames addObject:[methodInfo objectForKey:px_protocolMethodNameKey]];
+
+ return methodNames;
+}
+
+id px_methodNameForSelector(SEL selector)
+{
+ return NSStringFromSelector(selector);
+}
+
+struct objc_method_description px_methodDescriptionForProtocolMethod(Protocol *protocol, SEL selector)
+{
+ struct objc_method_description description = {NULL, NULL};
+
+ // We have 4 permutations to check for.
+ for (NSUInteger i = 0; i < 4; ++i) {
+ description = protocol_getMethodDescription(protocol, selector, (i / 2) % 2, i % 2);
+ if (description.types != NULL && description.name != NULL)
+ break;
+ }
+
+ return description;
+}
diff --git a/modules/gui/macosx/PXSourceList/PXSourceList.h b/modules/gui/macosx/PXSourceList/PXSourceList.h
new file mode 100755
index 0000000000..f5d278ac56
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceList.h
@@ -0,0 +1,206 @@
+//
+// PXSourceList.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 05/09/2009.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Cocoa/Cocoa.h>
+
+#import "PXSourceListDelegate.h"
+#import "PXSourceListDataSource.h"
+#import "PXSourceListItem.h"
+#import "PXSourceListBadgeView.h"
+#import "PXSourceListTableCellView.h"
+
+/**
+
+ `PXSourceList` is an `NSOutlineView` subclass that makes using a source list (the sidebar
+ seen in applications such as iTunes and Mail.app) easier by providing common styling and idiomatic
+ behaviour of source lists for you through a clean and simple API. Notable features of PXSourceList include:
+
+ - All root-level, "group" items are displayed using `NSOutlineView`'s group styling by default and requires no additional setup.
+ - Source List items often display an *icon* and *badge* (for information such as unread counts). This is built into
+ the API to make configuring these quick and easy, and a badge `NSControl` subclass is included which can be added to
+ `NSTableCellView` objects when using `PXSourceList` in *view-based* mode to display badges (see the next section for details).
+ - `PXSourceList` implements support for showing groups as "always expanded" -- where their child items are always shown
+ and no 'Show'/'Hide' button is displayed when hovering over the group. This is often useful for listing the main
+ contexts your application can be in at any given time, which the user can select to change views. As it is paramount to
+ your application's navigation, these groups are often displayed with their child items always shown.
+ - `PXSourceList` objects operate with only one column and do not display a header, something
+ which is reflected in the API and makes the control easier to use.
+
+ Like `NSOutlineView` and `NSTableView`, a `PXSourceList` object does not store its own data, but retrieves
+ values from a weakly-referenced data source (see the `PXSourceListDataSource` protocol). A `PXSourceList`
+ object can also have a delegate, to which it sends messages when certain events occur (see the
+ `PXSourceListDelegate` protocol for more information).
+
+ ### Cell-based vs. view-based mode
+
+ Like `NSTableView` and `NSOutlineView`, PXSourceList can operate in both cell-based and view-based mode in
+ relation to how you provide content to be displayed.
+
+ When using PXSourceList in cell-based mode, it can manage drawing of icons and badges for you through custom
+ drawing and `PXSourceListDataSource` methods. However, when using PXSourceList in view-based mode, it can't
+ do this directly, because cell views are configured independently in Interface Builder (or programmatically)
+ and configured in the `PXSourceListDataSource` method, `-sourceList:viewForItem:`.
+
+ Instead, in view-based mode, you should set up the icon for each item in `-sourceList:viewForItem:` using the
+ `imageView` property of `NSTableCellView`, and the `badgeView` property if using `PXSourceListTableCellView`
+ objects to display your content. Additionally, there are several classes provided alongside `PXSourceList`
+ which make this set up a lot easier:
+
+ - `PXSourceListTableCellView`: an `NSTableCellView` subclass which exposes a `badgeView` outlet that can be
+ hooked up to a `PXSourceListBadgeView` instance (see below) in Interface Builder. Along with `NSTableCellView`
+ and its `textField` and `imageView` properties, `PXSourceListTableCellView` is an `NSTableCellView` subclass which
+ allows you to easily display an icon, title and a badge for each item in the Source List without subclassing.
+ - `PXSourceListBadgeView`: a view class for displaying badges, which can be used in your table cell views and
+ configured to display a particular badge number. Additionally, instances can be configured to use custom text and
+ background colours, although it will use the regular Source List styling of light text on a grey-blue background
+ by default.
+
+ ### Creating a data source model with `PXSourceListItem`
+
+ Like `NSOutlineView`, PXSourceList queries its data source to build up a tree-like structure of content using
+ `-sourceList:numberOfChildrenOfItem:` and `-sourceList:child:ofItem:`. Often it is practical to store the structure
+ of your Source List content in a tree structure which can then be easily returned the the Source List using
+ these two data source methods.
+
+ To help with this, the generic `PXSourceListItem` class has been included with PXSourceList which can be
+ used to build this tree structure. It declares properties such as `title` and `icon` which are useful in
+ storing display information which can then be used in `-sourceList:viewForItem:` or `-sourceList:objectValueForItem:`,
+ as well as a `children` property with convenience methods for mutating its list of children. Take a look at the
+ `PXSourceListItem` documentation for more information, as well as the cell-based and view-based example
+ projects included for examples of how to use this class in your own projects.
+
+ */
+ at interface PXSourceList: NSOutlineView <NSOutlineViewDelegate, NSOutlineViewDataSource>
+
+///---------------------------------------------------------------------------------------
+/// @name Delegate and Data Source
+///---------------------------------------------------------------------------------------
+
+/** Used to set the Source List's data source.
+
+ @warning Unfortunately, due to the way that `PXSourceList` is implemented, sending `-dataSource` to the Source List
+ will return a proxy object which is used internally. As such you should only use this setter and not invoke `-dataSource`
+ to retrieve the data source object.
+
+ @param dataSource An object to use for the data source.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)setDataSource:(id<PXSourceListDataSource>)dataSource;
+
+/** Used to set the Source List's delegate.
+
+ @warning Unfortunately, due to the way that `PXSourceList` is implemented, sending `-delegate` to the Source List
+ will return a proxy object which is used internally. As such you should only use this setter and not invoke `-delegate`
+ to retrieve the data source object.
+
+ @param delegate An object to use for the delegate.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)setDelegate:(id<PXSourceListDelegate>)delegate;
+
+///---------------------------------------------------------------------------------------
+/// @name Setting Display Attributes
+///---------------------------------------------------------------------------------------
+
+/** Returns the size of icons in points to display in items in the Source List.
+
+ @discussion The default value is 16 x 16.
+
+ @warning This property only applies when using `PXSourceList` in cell-based mode. If set on a Source List
+ operating in view-based mode, this value is not used.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+
+ at property (nonatomic, assign) NSSize iconSize;
+
+///---------------------------------------------------------------------------------------
+/// @name Working with Groups
+///---------------------------------------------------------------------------------------
+
+ at property (readonly) NSUInteger numberOfGroups;
+
+/** Returns a Boolean value that indicates whether a given item in the Source List is a group item.
+
+ @param item The item to query about.
+
+ @return `YES` if *item* exists in the Source List and is a group item, otherwise `NO`.
+
+ @discussion "Group" items are defined as root items in the Source List tree hierarchy.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)isGroupItem:(id)item;
+
+/** Returns a Boolean value that indicates whether a given group item in the Source List is always expanded.
+
+ @param group The given group item.
+
+ @return `YES` if *group* is a group item in the Source List which is displayed as always expanded, or `NO` otherwise.
+
+ @discussion "Group" items are defined as root items in the Source List tree hierarchy. A group item that is displayed
+ as always expanded doesn't show a 'Show'/'Hide' button on hover as with regular group items. It is automatically expanded
+ when the Source List's data is reloaded and cannot be collapsed.
+
+ This method calls the `-sourceList:isGroupAlwaysExpanded:` method on the Source List's delegate to determine
+ whether the particular group item is displayed as always expanded or not.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)isGroupAlwaysExpanded:(id)group;
+
+///---------------------------------------------------------------------------------------
+/// @name Working with Badges
+///---------------------------------------------------------------------------------------
+
+/** Returns a Boolean value that indicates whether a given item in the Source List displays a badge.
+
+ @param item The given item.
+
+ @return `YES` if the Source List is operating in cell-based mode and *item* displays a badge, or `NO` otherwise.
+
+ @discussion This method calls the `-sourceList:itemHasBadge:` method on the Source List's delegate to determine
+ whether the item displays a badge or not.
+
+ @warning This method only applies when using a Source List in cell-based mode. If sent to a Source List in view-based mode, this
+ method returns `NO`.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)itemHasBadge:(id)item;
+
+/** Returns the integer value of the badge for a given item.
+
+ @param item The given item.
+
+ @return The integer value of the badge for *item* if the Source List is operating in cell-based mode and *item* displays a badge, or `NSNotFound` otherwise.
+
+ @discussion This method calls the `-sourceList:badgeValueForItem:` method on the Source List's data source to determine
+ the item's badge value.
+
+ @warning This method only applies when using a Source List in cell-based mode. If sent to a Source List in view-based mode, this
+ method returns `NSNotFound`.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSInteger)badgeValueForItem:(id)item;
+
+/* === Unavailable methods ===
+
+ As a side-effect of PXSourceList's internal implementation, these methods shouldn't be used to query the delegate or data
+ source. I am *always* looking for a way to remove this limitation. Please file an issue at https://github.com/Perspx/PXSourceList if you
+ have any ideas!
+ */
+- (id <NSOutlineViewDelegate>)delegate __attribute__((unavailable("-delegate shouldn't be called on PXSourceList. See the documentation for more information.")));
+- (id <NSOutlineViewDataSource>)dataSource __attribute__((unavailable("-dataSource shouldn't be called on PXSourceList. See the documentation for more information.")));
+
+ at end
+
diff --git a/modules/gui/macosx/PXSourceList/PXSourceList.m b/modules/gui/macosx/PXSourceList/PXSourceList.m
new file mode 100755
index 0000000000..fd7f74b419
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceList.m
@@ -0,0 +1,578 @@
+//
+// PXSourceList.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 05/09/2009.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceList.h"
+#import "PXSourceListBadgeCell.h"
+#import "Internal/PXSourceListDelegateDataSourceProxy.h"
+#import "Internal/PXSourceListPrivateConstants.h"
+
+//Layout constants
+static const CGFloat minBadgeWidth = 22.0; // The minimum badge width for each item (default 22.0).
+static const CGFloat badgeHeight = 14.0; // The badge height for each item (default 14.0).
+static const CGFloat rowRightMargin = 5.0; // The spacing between the right edge of the badge and the edge of the table column.
+static const CGFloat iconSpacing = 2.0; // The spacing between the icon and it's adjacent cell.
+static const CGFloat disclosureTriangleSpace = 18.0; // The indentation reserved for disclosure triangles for non-group items.
+
+//Delegate notification constants
+NSString * const PXSLSelectionIsChangingNotification = @"PXSourceListSelectionIsChanging";
+NSString * const PXSLSelectionDidChangeNotification = @"PXSourceListSelectionDidChange";
+NSString * const PXSLItemWillExpandNotification = @"PXSourceListItemWillExpand";
+NSString * const PXSLItemDidExpandNotification = @"PXSourceListItemDidExpand";
+NSString * const PXSLItemWillCollapseNotification = @"PXSourceListItemWillCollapse";
+NSString * const PXSLItemDidCollapseNotification = @"PXSourceListItemDidCollapse";
+NSString * const PXSLDeleteKeyPressedOnRowsNotification = @"PXSourceListDeleteKeyPressedOnRows";
+
+#pragma mark -
+ at interface PXSourceList ()
+
+ at property (strong, nonatomic) PXSourceListDelegateDataSourceProxy *delegateDataSourceProxy;
+ at property (strong, readonly) PXSourceListBadgeCell *reusableBadgeCell;
+
+ at end
+
+#pragma mark -
+ at implementation PXSourceList
+
+ at synthesize reusableBadgeCell = _reusableBadgeCell;
+
+#pragma mark - Setup/Teardown
+
+- (id)initWithCoder:(NSCoder*)decoder
+{
+ if(self=[super initWithCoder:decoder]) {
+ [self PXSL_setup];
+ }
+
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frameRect
+{
+ if((self = [super initWithFrame:frameRect])) {
+ [self PXSL_setup];
+ }
+
+ return self;
+}
+
+- (void)PXSL_setup
+{
+ _iconSize = NSMakeSize(16,16);
+ _delegateDataSourceProxy = [[PXSourceListDelegateDataSourceProxy alloc] initWithSourceList:self];
+}
+
+- (void)dealloc
+{
+ _delegateDataSourceProxy = nil;
+ //Remove ourselves as the delegate and data source to be safe
+ [super setDataSource:nil];
+ [super setDelegate:nil];
+}
+
+
+#pragma mark -
+#pragma mark Custom Accessors
+
+- (void)setDelegate:(id<PXSourceListDelegate>)aDelegate
+{
+ self.delegateDataSourceProxy.delegate = aDelegate;
+
+ [super setDelegate:nil];
+ if (aDelegate)
+ [super setDelegate:self.delegateDataSourceProxy];
+}
+
+
+- (void)setDataSource:(id<PXSourceListDataSource>)aDataSource
+{
+ self.delegateDataSourceProxy.dataSource = aDataSource;
+
+ [super setDataSource:nil];
+ if (aDataSource)
+ [super setDataSource:self.delegateDataSourceProxy];
+
+ [self reloadData];
+}
+
+- (void)setIconSize:(NSSize)newIconSize
+{
+ _iconSize = newIconSize;
+
+ CGFloat rowHeight = [self rowHeight];
+
+ //Make sure icon height does not exceed row height; if so constrain, keeping width and height in proportion
+ if(_iconSize.height>rowHeight)
+ {
+ _iconSize.width = _iconSize.width * (rowHeight/_iconSize.height);
+ _iconSize.height = rowHeight;
+ }
+}
+
+- (PXSourceListBadgeCell *)reusableBadgeCell
+{
+ if (!_reusableBadgeCell)
+ _reusableBadgeCell = [[PXSourceListBadgeCell alloc] init];
+
+ return _reusableBadgeCell;
+}
+
+- (BOOL)floatsGroupRows
+{
+ return NO;
+}
+
+- (void)setFloatsGroupRows:(BOOL)value
+{
+ [super setFloatsGroupRows:NO];
+}
+
+#pragma mark -
+#pragma mark Data Management
+
+- (BOOL)isViewBasedSourceList
+{
+ return [self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:viewForItem:)];
+}
+
+- (void)reloadData
+{
+ [super reloadData];
+
+ //Expand items that are displayed as always expanded
+ if([self.delegateDataSourceProxy conformsToProtocol:@protocol(PXSourceListDataSource)] &&
+ [self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:isGroupAlwaysExpanded:)])
+ {
+ for(NSUInteger i=0;i<[self numberOfGroups];i++)
+ {
+ id item = [self.delegateDataSourceProxy sourceList:self child:i ofItem:nil];
+
+ if([self isGroupAlwaysExpanded:item]) {
+ [self expandItem:item expandChildren:NO];
+ }
+ }
+
+ }
+
+ //If there are selected rows and the item hierarchy has changed, make sure a Group row isn't
+ //selected
+ if([self numberOfSelectedRows]>0) {
+ NSIndexSet *selectedIndexes = [self selectedRowIndexes];
+ NSUInteger firstSelectedRow = [selectedIndexes firstIndex];
+
+ //Is a group item selected?
+ if([self isGroupItem:[self itemAtRow:firstSelectedRow]]) {
+ //Work backwards to find the first non-group row
+ BOOL foundRow = NO;
+ for(NSUInteger i=firstSelectedRow;i>0;i--)
+ {
+ if(![self isGroupItem:[self itemAtRow:i]]) {
+ [self selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];
+ foundRow = YES;
+ break;
+ }
+ }
+
+ //If there is no non-group row preceding the currently selected group item, remove the selection
+ //from the Source List
+ if(!foundRow) {
+ [self deselectAll:self];
+ }
+ }
+ }
+ else if(![self allowsEmptySelection]&&[self numberOfSelectedRows]==0)
+ {
+ //Select the first non-group row if no rows are selected, and empty selection is disallowed
+ for(NSUInteger i=0;i<[self numberOfRows];i++)
+ {
+ if(![self isGroupItem:[self itemAtRow:i]]) {
+ [self selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];
+ break;
+ }
+ }
+ }
+}
+
+- (NSUInteger)numberOfGroups
+{
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:numberOfChildrenOfItem:)]) {
+ return [self.delegateDataSourceProxy sourceList:self numberOfChildrenOfItem:nil];
+ }
+
+ return 0;
+}
+
+
+- (BOOL)isGroupItem:(id)item
+{
+ //Groups are defined as root items (at level 0)
+ return 0==[self levelForItem:item];
+}
+
+
+- (BOOL)isGroupAlwaysExpanded:(id)group
+{
+ //Make sure that the item IS a group to prevent unwanted queries sent to the data source
+ if([self isGroupItem:group]) {
+ //Query the data source
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:isGroupAlwaysExpanded:)]) {
+ return [self.delegateDataSourceProxy sourceList:self isGroupAlwaysExpanded:group];
+ }
+ }
+
+ return NO;
+}
+
+
+- (BOOL)itemHasBadge:(id)item
+{
+ // Since badges are managed by custom views and logic in view-based mode, we can't determine this.
+ if (self.isViewBasedSourceList)
+ return NO;
+
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:itemHasBadge:)]) {
+ return [self.delegateDataSourceProxy sourceList:self itemHasBadge:item];
+ }
+
+ return NO;
+}
+
+- (NSInteger)badgeValueForItem:(id)item
+{
+ // Since badges are managed by custom views and logic in view-based mode, we can't determine this.
+ if (self.isViewBasedSourceList || ![self itemHasBadge:item])
+ return NSNotFound;
+
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:badgeValueForItem:)]) {
+ return [self.delegateDataSourceProxy sourceList:self badgeValueForItem:item];
+ }
+
+ return NSNotFound;
+}
+
+#pragma mark -
+#pragma mark Selection Handling
+
+- (void)selectRowIndexes:(NSIndexSet*)indexes byExtendingSelection:(BOOL)extend
+{
+ NSUInteger numberOfIndexes = [indexes count];
+
+ //Prevent empty selection if we don't want it
+ if(![self allowsEmptySelection]&&0==numberOfIndexes) {
+ return;
+ }
+
+ //Would use blocks but we're also targeting 10.5...
+ //Get the selected indexes
+ NSUInteger *selectedIndexes = malloc(sizeof(NSUInteger)*numberOfIndexes);
+ [indexes getIndexes:selectedIndexes maxCount:numberOfIndexes inIndexRange:nil];
+
+ //Loop through the indexes and only add non-group row indexes
+ //Allows selection across groups without selecting the group rows
+ NSMutableIndexSet *newSelectionIndexes = [NSMutableIndexSet indexSet];
+ for(NSInteger i=0;i<numberOfIndexes;i++)
+ {
+ if(![self isGroupItem:[self itemAtRow:selectedIndexes[i]]]) {
+ [newSelectionIndexes addIndex:selectedIndexes[i]];
+ }
+ }
+
+ //If there are any non-group rows selected
+ if([newSelectionIndexes count]>0) {
+ [super selectRowIndexes:newSelectionIndexes byExtendingSelection:extend];
+ }
+
+ //C memory management... *sigh*
+ free(selectedIndexes);
+}
+
+#pragma mark -
+#pragma mark Layout
+
+- (NSRect)frameOfOutlineCellAtRow:(NSInteger)row
+{
+ //Return a zero-rect if the item is always expanded (a disclosure triangle will not be drawn)
+ if([self isGroupAlwaysExpanded:[self itemAtRow:row]]) {
+ return NSZeroRect;
+ }
+
+ NSRect frame = [super frameOfOutlineCellAtRow:row];
+
+ if([self levelForRow:row] > 0) {
+ frame.origin.x = [self levelForRow:row] * [self indentationPerLevel];
+ }
+
+ return frame;
+}
+
+
+- (NSRect)frameOfCellAtColumn:(NSInteger)column row:(NSInteger)row
+{
+ if (self.isViewBasedSourceList)
+ return [super frameOfCellAtColumn:column row:row];
+
+ id item = [self itemAtRow:row];
+
+ NSCell *cell = [self preparedCellAtColumn:column row:row];
+ NSSize cellSize = [cell cellSize];
+ if (!([cell type] == NSImageCellType) && !([cell type] == NSTextCellType))
+ cellSize = [cell cellSizeForBounds:[super frameOfCellAtColumn:column row:row]];
+ NSRect cellFrame = [super frameOfCellAtColumn:column row:row];
+
+ NSRect rowRect = [self rectOfRow:row];
+
+ if([self isGroupItem:item])
+ {
+ CGFloat minX = NSMinX(cellFrame);
+
+ //Set the origin x-coord; if there are no children of the group at current, there will still be a
+ //margin to the left of the cell (in cellFrame), which we don't want
+ if([self isGroupAlwaysExpanded:[self itemAtRow:row]]) {
+ minX = 7;
+ }
+
+ return NSMakeRect(minX,
+ NSMidY(cellFrame)-(cellSize.height/2.0),
+ NSWidth(rowRect)-minX,
+ cellSize.height);
+ }
+ else
+ {
+ CGFloat leftIndent = [self levelForRow:row]*[self indentationPerLevel]+disclosureTriangleSpace;
+
+ //Calculate space left for a badge if need be
+ CGFloat rightIndent = [self sizeOfBadgeAtRow:row].width+rowRightMargin;
+
+ //Allow space for an icon if need be
+ if(![self isGroupItem:item] && [self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:itemHasIcon:)])
+ {
+ if([self.delegateDataSourceProxy sourceList:self itemHasIcon:item]) {
+ leftIndent += [self iconSize].width+(iconSpacing*2);
+ }
+ }
+
+ return NSMakeRect(leftIndent,
+ NSMidY(rowRect)-(cellSize.height/2.0),
+ NSWidth(rowRect)-rightIndent-leftIndent,
+ cellSize.height);
+ }
+}
+
+
+//This method calculates and returns the size of the badge for the row index passed to the method. If the
+//row for the row index passed to the method does not have a badge, then NSZeroSize is returned.
+- (NSSize)sizeOfBadgeAtRow:(NSInteger)rowIndex
+{
+ id rowItem = [self itemAtRow:rowIndex];
+
+ if (![self itemHasBadge:rowItem])
+ return NSZeroSize;
+
+ self.reusableBadgeCell.integerValue = [self badgeValueForItem:rowItem];
+
+ return NSMakeSize(fmax(self.reusableBadgeCell.cellSize.width, minBadgeWidth), badgeHeight);
+}
+
+- (void)viewDidMoveToSuperview
+{
+ //If set to YES, this will cause display issues in Lion where the right part of the outline view is cut off
+ [self setAutoresizesOutlineColumn:NO];
+}
+
+#pragma mark -
+#pragma mark Drawing
+
+- (void)drawRow:(NSInteger)rowIndex clipRect:(NSRect)clipRect
+{
+ [super drawRow:rowIndex clipRect:clipRect];
+
+ // We only do drawing here if the Source List is cell-based.
+ if (self.isViewBasedSourceList)
+ return;
+
+ id item = [self itemAtRow:rowIndex];
+
+ //Draw an icon if the item has one
+ if(![self isGroupItem:item] && [self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:itemHasIcon:)])
+ {
+ if([self.delegateDataSourceProxy sourceList:self itemHasIcon:item])
+ {
+ NSRect cellFrame = [self frameOfCellAtColumn:0 row:rowIndex];
+ NSSize iconSize = [self iconSize];
+ NSRect iconRect = NSMakeRect(NSMinX(cellFrame)-iconSize.width-iconSpacing,
+ NSMidY(cellFrame)-(iconSize.height/2.0f),
+ iconSize.width,
+ iconSize.height);
+
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:iconForItem:)])
+ {
+ NSImage *icon = [self.delegateDataSourceProxy sourceList:self iconForItem:item];
+
+ if(icon!=nil)
+ {
+ NSSize actualIconSize = [icon size];
+
+ //If the icon is *smaller* than the size retrieved from the -iconSize property, make sure we
+ //reduce the size of the rectangle to draw the icon in, so that it is not stretched.
+ if((actualIconSize.width<iconSize.width)||(actualIconSize.height<iconSize.height))
+ {
+ iconRect = NSMakeRect(NSMidX(iconRect)-(actualIconSize.width/2.0f),
+ NSMidY(iconRect)-(actualIconSize.height/2.0f),
+ actualIconSize.width,
+ actualIconSize.height);
+ }
+
+ [icon drawInRect:iconRect
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1
+ respectFlipped:YES hints:nil];
+ }
+ }
+ }
+ }
+
+ //Draw the badge if the item has one
+ if([self itemHasBadge:item])
+ {
+ NSRect rowRect = [self rectOfRow:rowIndex];
+ NSSize badgeSize = [self sizeOfBadgeAtRow:rowIndex];
+
+ NSRect badgeFrame = NSMakeRect(NSMaxX(rowRect)-badgeSize.width-rowRightMargin,
+ NSMidY(rowRect)-(badgeSize.height/2.0),
+ badgeSize.width,
+ badgeSize.height);
+
+ [self drawBadgeForRow:rowIndex inRect:badgeFrame];
+ }
+}
+
+- (void)drawBadgeForRow:(NSInteger)rowIndex inRect:(NSRect)badgeFrame
+{
+ id rowItem = [self itemAtRow:rowIndex];
+
+ self.reusableBadgeCell.badgeValue = [self badgeValueForItem:rowItem];
+ if ([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:badgeTextColorForItem:)])
+ self.reusableBadgeCell.textColor = [self.delegateDataSourceProxy sourceList:self badgeTextColorForItem:rowItem];
+ if ([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:badgeBackgroundColorForItem:)])
+ self.reusableBadgeCell.textColor = [self.delegateDataSourceProxy sourceList:self badgeBackgroundColorForItem:rowItem];
+ self.reusableBadgeCell.highlighted = [self.selectedRowIndexes containsIndex:rowIndex];
+
+ [self.reusableBadgeCell drawWithFrame:badgeFrame inView:self];
+}
+
+#pragma mark -
+#pragma mark Keyboard Handling
+
+- (void)keyDown:(NSEvent *)theEvent
+{
+ NSIndexSet *selectedIndexes = [self selectedRowIndexes];
+
+ NSString *keyCharacters = [theEvent characters];
+
+ //Make sure we have a selection
+ if([selectedIndexes count]>0)
+ {
+ if([keyCharacters length]>0)
+ {
+ unichar firstKey = [keyCharacters characterAtIndex:0];
+
+ if(firstKey==NSUpArrowFunctionKey||firstKey==NSDownArrowFunctionKey)
+ {
+ //Handle keyboard navigation across groups
+ if([selectedIndexes count]==1&&!([theEvent modifierFlags] & NSShiftKeyMask))
+ {
+ int delta = firstKey==NSDownArrowFunctionKey?1:-1; //Search "backwards" if up arrow, "forwards" if down
+ NSInteger newRow = [selectedIndexes firstIndex];
+
+ //Keep incrementing/decrementing the row until a non-header row is reached
+ do {
+ newRow+=delta;
+
+ //If out of bounds of the number of rows..
+ if(newRow<0||newRow==[self numberOfRows])
+ break;
+ } while([self isGroupItem:[self itemAtRow:newRow]]);
+
+
+ [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
+ return;
+ }
+ }
+ else if(firstKey==NSDeleteCharacter||firstKey==NSBackspaceCharacter||firstKey==0xf728)
+ {
+ //Post the notification
+ [[NSNotificationCenter defaultCenter] postNotificationName:PXSLDeleteKeyPressedOnRowsNotification
+ object:self
+ userInfo:[NSDictionary dictionaryWithObject:selectedIndexes forKey:@"rows"]];
+
+ return;
+ }
+ }
+ }
+
+ //We don't care about it
+ [super keyDown:theEvent];
+}
+
+#pragma mark -
+#pragma mark Menu Handling
+
+
+- (NSMenu *)menuForEvent:(NSEvent *)theEvent
+{
+ NSMenu * m = nil;
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:menuForEvent:item:)]) {
+ NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+ NSInteger row = [self rowAtPoint:clickPoint];
+ id clickedItem = [self itemAtRow:row];
+ m = [self.delegateDataSourceProxy sourceList:self menuForEvent:theEvent item:clickedItem];
+ }
+ if (m == nil) {
+ m = [super menuForEvent:theEvent];
+ }
+ return m;
+}
+
+#pragma mark - Custom NSOutlineView Delegate Method Implementations
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item
+{
+ // Make sure the item isn't displayed as always expanded
+ if([self isGroupItem:item] && [self isGroupAlwaysExpanded:item])
+ return NO;
+
+ if([self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:shouldCollapseItem:)])
+ return [self.delegateDataSourceProxy sourceList:self shouldCollapseItem:item];
+
+ return YES;
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
+{
+ // Make sure that the item isn't a group as they can't be selected
+ if(![self isGroupItem:item] && [self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:shouldSelectItem:)])
+ return [self.delegateDataSourceProxy sourceList:self shouldSelectItem:item];
+
+ return ![self isGroupItem:item];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ if(![self isGroupItem:item] && [self.delegateDataSourceProxy respondsToSelector:@selector(sourceList:shouldEditItem:)])
+ return [self.delegateDataSourceProxy sourceList:self shouldEditItem:item];
+
+ return ![self isGroupItem:item];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
+{
+ return [self isGroupItem:item];
+}
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.h b/modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.h
new file mode 100755
index 0000000000..e08e6a970f
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.h
@@ -0,0 +1,23 @@
+//
+// PXSourceListBadgeCell.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 15/11/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Cocoa/Cocoa.h>
+
+/* This is the cell which backs drawing done by PXSourceListBadgeView, and is used internally for
+ drawing badges when PXSourceList is used in cell-based mode.
+
+ You shouldn't need to interact with this class directly.
+ */
+ at interface PXSourceListBadgeCell : NSCell
+
+ at property (strong, nonatomic) NSColor *textColor;
+ at property (strong, nonatomic) NSColor *backgroundColor;
+ at property (assign, nonatomic) NSUInteger badgeValue;
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.m b/modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.m
new file mode 100755
index 0000000000..a1f0786898
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListBadgeCell.m
@@ -0,0 +1,122 @@
+//
+// PXSourceListBadgeCell.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 15/11/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceListBadgeCell.h"
+
+#import "PXSourceList.h"
+
+//Drawing constants
+static inline NSColor *badgeBackgroundColor() { return [NSColor colorWithCalibratedRed:(152/255.0) green:(168/255.0) blue:(202/255.0) alpha:1]; }
+static inline NSColor *badgeHiddenBackgroundColor() { return [NSColor colorWithDeviceWhite:(180/255.0) alpha:1]; }
+static inline NSColor *badgeSelectedTextColor() { return [NSColor keyboardFocusIndicatorColor]; }
+static inline NSColor *badgeSelectedUnfocusedTextColor() { return [NSColor colorWithCalibratedRed:(153/255.0) green:(169/255.0) blue:(203/255.0) alpha:1]; }
+static inline NSColor *badgeSelectedHiddenTextColor() { return [NSColor colorWithCalibratedWhite:(170/255.0) alpha:1]; }
+static inline NSFont *badgeFont() { return [NSFont boldSystemFontOfSize:11]; }
+
+// Sizing constants.
+static const CGFloat badgeLeftAndRightPadding = 5.0;
+
+ at implementation PXSourceListBadgeCell
+
+- (id)init
+{
+ if (!(self = [super initTextCell:@""]))
+ return nil;
+
+ return self;
+}
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
+{
+ CGFloat borderRadius = NSHeight(cellFrame)/2.0f;
+ NSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius:borderRadius yRadius:borderRadius];
+
+ // Get the window and control state to determine the badge colours used.
+ BOOL isMainWindowVisible = [[NSApp mainWindow] isVisible];
+ NSDictionary *attributes;
+ NSColor *backgroundColor;
+
+ if(self.isHighlighted || self.backgroundStyle == NSBackgroundStyleDark) {
+ backgroundColor = [NSColor whiteColor];
+
+ NSResponder *firstResponder = controlView.window.firstResponder;
+ BOOL isFocused = NO;
+
+ // Starting with the closest ancestor of the control view and the first responder (to make sure both views are in the
+ // same subtree of the view hierarchy), keep going up the view hierarchy until we hit a PXSourceList instance to tell
+ // if the source list is focused.
+ // This covers both the cell-based and view-based cases as well as if a child view of the NSTableCellView (such as
+ // a text field) is focused.
+ if ([firstResponder isKindOfClass:[NSView class]]) {
+ NSView *view = [(NSView*)firstResponder ancestorSharedWithView:controlView];
+ do {
+ if ([view isKindOfClass:[PXSourceList class]]) {
+ isFocused = YES;
+ break;
+ }
+ } while ((view = [view superview]));
+ }
+
+ NSColor *textColor;
+
+ if (isMainWindowVisible && isFocused)
+ textColor = badgeSelectedTextColor();
+ else if (isMainWindowVisible && !isFocused)
+ textColor = badgeSelectedUnfocusedTextColor();
+ else
+ textColor = badgeSelectedHiddenTextColor();
+
+ attributes = @{NSForegroundColorAttributeName: textColor};
+ } else {
+ NSColor *textColor = textColor = self.textColor ? self.textColor : [NSColor whiteColor];;
+
+ if(isMainWindowVisible)
+ backgroundColor = self.backgroundColor ? self.backgroundColor : badgeBackgroundColor();
+ else
+ backgroundColor = badgeHiddenBackgroundColor();
+
+ attributes = @{NSForegroundColorAttributeName: textColor};
+ }
+
+ [backgroundColor set];
+ [badgePath fill];
+
+ //Draw the badge text
+ NSMutableAttributedString *badgeString = [self.badgeString mutableCopy];
+ [badgeString addAttributes:attributes range:NSMakeRange(0, badgeString.length)];
+
+ NSSize stringSize = badgeString.size;
+ NSPoint badgeTextPoint = NSMakePoint(NSMidX(cellFrame) - (stringSize.width/2.0),
+ NSMidY(cellFrame) - (stringSize.height/2.0));
+ [badgeString drawAtPoint:badgeTextPoint];
+}
+
+- (NSSize)cellSize
+{
+ NSSize size = self.badgeString.size;
+ size.width += 2 * badgeLeftAndRightPadding;
+
+ return size;
+}
+
+- (NSAttributedString *)badgeString
+{
+ return [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%ld", self.badgeValue]
+ attributes:@{NSFontAttributeName: badgeFont()}];
+}
+
+- (id)accessibilityAttributeValue:(NSString *)attribute
+{
+ if ([attribute isEqualToString:NSAccessibilityValueAttribute])
+ return @(_badgeValue).description;
+ else
+ return [super accessibilityAttributeValue:attribute];
+}
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListBadgeView.h b/modules/gui/macosx/PXSourceList/PXSourceListBadgeView.h
new file mode 100755
index 0000000000..6083dcaf63
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListBadgeView.h
@@ -0,0 +1,72 @@
+//
+// PXSourceListBadgeView.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 15/11/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Cocoa/Cocoa.h>
+
+/**
+ `PXSourceListBadgeView` is an `NSControl` subclass which can be used for displaying Source List badges.
+
+ @discussion Instances of this class can be used by table cell views which are used to display content when
+ using `PXSourceList` in view-based mode. These table cell views have to be set up to display badges in the
+ `PXSourceListDataSource` method `-sourceList:viewForItem:` unlike when using `PXSourceList` in cell-based mode,
+ where this is done automatically behind-the-scenes.
+
+ `PXSourceListTableCellView` has an outlet for a `PXSourceListBadgeView` instance which can be hooked up in Interface
+ Builder or set in code.
+
+ ### Display customisation
+
+ `PXSourceListBadgeView` displays badges like a 'system default' Source List such as in Mail.app with a grey-blue
+ background and light text. However, the colours used for the badge value and the background colour of the badge can be
+ changed by using the `textColor` and `backgroundColor` properties.
+
+ @warning Note that the `textColor` and `backgroundColor` properties are only respected when the row displaying the badge
+ isn't highlighted. When the row is highlighted, the badge is displayed with a white background and a blue text colour.
+
+ */
+ at interface PXSourceListBadgeView : NSControl
+
+///---------------------------------------------------------------------------------------
+/// @name Reading and setting the badge value
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the numeric value displayed by the receiver.
+
+ @since Requires the Mac OS X 10.7 SDK or above.
+ */
+ at property (assign, nonatomic) NSUInteger badgeValue;
+
+///---------------------------------------------------------------------------------------
+/// @name Customising the badge appearance
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the custom text colour used to display the receiver.
+ @discussion The default value for this property is `nil`. Set this property to `nil` to use the default light badge text colour.
+
+ @see backgroundColor
+
+ @warning Note that this property is only respected when the row displaying the badge isn't highlighted. When the row is highlighted, the badge is displayed with a blue text colour.
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+ at property (strong, nonatomic) NSColor *textColor;
+
+/**
+ @brief Returns the custom background colour used to display the receiver.
+ @discussion The default value for this property is `nil`. Set this property to `nil` to use the default grey-blue badge background colour.
+
+ @see textColor
+
+ @warning Note that this property is only respected when the row displaying the badge isn't highlighted. When the row is highlighted, the badge is displayed with a white background colour.
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+ at property (strong, nonatomic) NSColor *backgroundColor;
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListBadgeView.m b/modules/gui/macosx/PXSourceList/PXSourceListBadgeView.m
new file mode 100755
index 0000000000..8d13ab9d50
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListBadgeView.m
@@ -0,0 +1,52 @@
+//
+// PXSourceListBadgeView.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 15/11/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceListBadgeView.h"
+#import "PXSourceListBadgeCell.h"
+
+ at implementation PXSourceListBadgeView
+
++ (Class)cellClass
+{
+ return [PXSourceListBadgeCell class];
+}
+
+#pragma mark - Custom Accessors
+
+- (void)setBadgeValue:(NSUInteger)badgeValue
+{
+ [self.cell setBadgeValue:badgeValue];
+}
+
+- (NSUInteger)badgeValue
+{
+ return [self.cell badgeValue];
+}
+
+- (NSColor *)textColor
+{
+ return [self.cell textColor];
+}
+
+- (void)setTextColor:(NSColor *)textColor
+{
+ [self.cell setTextColor:textColor];
+}
+
+- (NSColor *)backgroundColor
+{
+ return [self.cell backgroundColor];
+}
+
+- (void)setBackgroundColor:(NSColor *)backgroundColor
+{
+ [self.cell setBackgroundColor:backgroundColor];
+}
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListDataSource.h b/modules/gui/macosx/PXSourceList/PXSourceListDataSource.h
new file mode 100755
index 0000000000..4152adc431
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListDataSource.h
@@ -0,0 +1,396 @@
+//
+// PXSourceListDataSource.h
+// PXViewKit
+//
+// Created by Alex Rozanski on 17/10/2009.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Cocoa/Cocoa.h>
+
+ at class PXSourceList;
+
+/**
+ The `PXSourceListDataSource` protocol defines methods that can be implemented by data sources of `PXSourceList` objects.
+
+ Despite many of these methods being optional in their implementation, several methods **must** be implemented by a data source of a `PXSourceList` object. These are:
+
+ - `sourceList:numberOfChildrenOfItem:`
+ - `sourceList:child:ofItem:`
+ - `sourceList:isItemExpandable:`
+ - `sourceList:objectValueForItem:` (although this is optional if the Source List is operating in view-based mode).
+
+ ### PXSourceList in View-based mode
+
+ As with `NSOutlineView`, `PXSourceList` can operate in cell-based or view-based mode. Of particular note, the
+ following `PXSourceListDataSource` methods are *not* used by `PXSourceList` when operating in view-based mode.
+
+ - `-sourceList:itemHasBadge:`
+ - `-sourceList:badgeValueForItem:`
+ - `-sourceList:badgeTextColorForItem:`
+ - `-sourceList:badgeBackgroundColorForItem:`
+ - `-sourceList:itemHasIcon:`
+ - `-sourceList:iconForItem:`
+
+ These properties can be configured in the `PXSourceListDelegate` protocol method, `-sourceList:viewForItem:`.
+
+ @warning Most of the methods defined by this protocol are analagous to those declared by `NSOutlineViewDataSource` (and are marked as such in the member's documentation), but are prefixed by "sourceList:" instead of "outlineView:". Only the most basic information about these methods is included here, and you should refer to the `NSOutlineViewDataSource` protocol documentation for more information.
+ */
+ at protocol PXSourceListDataSource <NSObject>
+
+ at required
+///---------------------------------------------------------------------------------------
+/// @name Working with Items in a Source List
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the number of child items of a given item.
+
+ @param sourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The number of immediate child items of *item*. If *item* is `nil` then you should return the number of top-level items in the Source List item hierarchy.
+
+ @since Requires PXSourceList 0.8 and above and the OS X v10.5 SDK or above.
+
+ @see sourceList:child:ofItem:
+ */
+- (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item;
+
+/**
+ @brief Returns the direct child of a given item at the specified index.
+
+ @param aSourceList The Source List that sent the message.
+ @param index The index of the child item of *item* to return.
+ @param item An item in the data source.
+
+ @return The immediate child of *item* at the specified *index*. If *item* is `nil`, then return the top-level item with index of *index*.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+
+ @see sourceList:numberOfChildrenOfItem:
+ */
+- (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item;
+
+/**
+ @brief Returns a Boolean value indicating whether a given item in the Source List is expandable.
+ @discussion An expandable item is one which contains child items, and can be expanded to display these. Additionally, if a group item is always displayed as expanded (denoted by `-sourceList:isGroupAlwaysExpanded:` from the `PXSourceListDelegate` protocol) then you must return `YES` from this method for the given group item.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` if *item* can be expanded, or `NO` otherwise.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item;
+
+ at optional
+/**
+ @brief Returns the data object associated with a given item.
+ @discussion When using the Source List in cell-based mode, returning the text to be displayed for cells representing Group items, the Source List will *not* transform the titles to uppercase so that they display like in iTunes or iCal, such as "LIBRARY". This is to account for edge cases such as words like "iTunes" which should be capitalized as "iTUNES" and so to do this you must pass uppercase titles yourself. It is strongly recommended that text displayed for group items is uppercased in this way, to fit the conventional style of Source List Group headers.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The data object associated with `item`.
+
+ @warning This is a required method when using the Source List in cell-based mode.
+
+ @see sourceList:setObjectValue:forItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item;
+
+/**
+ @brief Sets the associated object value of a specified item.
+ @discussion This method must be implemented if the Source List is operating in cell-based mode and any items in the Source List are editable.
+
+ @param aSourceList The Source List that sent the message.
+ @param object The new object value for the given item.
+ @param item An item in the data source.
+
+ @see sourceList:objectValueForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Working with Badges
+///---------------------------------------------------------------------------------------
+
+/**
+ @brief Returns a Boolean specifying whether a given item shows a badge or not.
+ @discussion This method can be implemented by the data source to specify whether a given item displays a badge or not. A badge is a rounded rectangle containing a number (the badge value), displayed to the right of a row's cell.
+
+ This method must be implemented for the other badge-related data source methods – sourceList:badgeValueForItem:, sourceList:badgeTextColorForItem: and sourceList:badgeBackgroundColorForItem: – to be called.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` if *item* should display a badge, or `NO` otherwise.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, the view for each cell is responsible for managing a badge, if applicable.
+
+ @see sourceList:badgeValueForItem:
+ @see sourceList:badgeTextColorForItem:
+ @see sourceList:badgeBackgroundColorForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item;
+
+/**
+ @brief Returns an integer specifying the badge value for a particular item.
+ @discussion This method can be implemented by the data source to specify a badge value for any particular item. If you want an item to display a badge, you must also implement sourceList:itemHasBadge: and return `YES` for that item. Returning `NO` for items in sourceList:itemHasBadge: means that this method will not be called for that item.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The badge value for *item*.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, the view for each cell is responsible for managing a badge, if applicable.
+
+ @see sourceList:itemHasBadge:
+ @see sourceList:badgeTextColorForItem:
+ @see sourceList:badgeBackgroundColorForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item;
+
+/**
+ @brief Returns a color that is used for the badge text color of an item in the Source List.
+ @discussion This method can be implemented by the data source to specify a custom badge color for a particular item.
+
+ This method is only called for *item* if you return `YES` for *item* in sourceList:itemHasBadge:.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return An `NSColor` object to use for the text color of *item*'s badge or `nil` to use the default badge text color.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, the view for each cell is responsible for managing a badge, if applicable.
+
+ @see sourceList:itemHasBadge:
+ @see sourceList:badgeValueForItem:
+ @see sourceList:badgeBackgroundColorForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSColor*)sourceList:(PXSourceList*)aSourceList badgeTextColorForItem:(id)item;
+
+/**
+ @brief Returns a color that is used for the badge background color of an item in the Source List.
+ @discussion This method can be implemented by the data source to specify a custom badge background color for a particular item.
+
+ This method is only called for *item* if you return `YES` for *item* in sourceList:itemHasBadge:.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return An `NSColor` object to use for the background color of *item*'s badge or `nil` to use the default badge background color.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, the view for each cell is responsible for managing a badge, if applicable.
+
+ @see sourceList:itemHasBadge:
+ @see sourceList:badgeValueForItem:
+ @see sourceList:badgeTextColorForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSColor*)sourceList:(PXSourceList*)aSourceList badgeBackgroundColorForItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Working with Icons
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value that indicates whether a given item shows an icon or not.
+ @discussion This method can be implemented by the data source to specify whether items contain icons or not. Icons are images which are shown to the left of the row's cell, and provide a visual which accompanies the cell.
+
+ This method must be implemented if you want to return an icon with `sourceList:iconForItem:`.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` if *item* displays an icon, or `NO` otherwise.
+
+ @warning This method is only used and invoked by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, the view for each cell is responsible for managing its icon, if applicable.
+
+ @see sourceList:iconForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item;
+
+/**
+ @brief Returns the icon for a given item in the Source List.
+ @discussion This method must be implemented by the data source if you return `YES` in `sourceList:itemHasIcon:` for any item in the Source List.
+
+ The maximum size of each icon is specified with the Source List's `iconSize` property. If the returned image is larger than the icon size property on the Source List, then it is proportionally resized down to fit this size.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return An `NSImage` that is to be used for the icon for *item*.
+
+ @warning This method is only used and invoked by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, the view for each cell is responsible for managing its icon, if applicable.
+
+ @see sourceList:itemHasIcon:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item;
+
+//The rest of these methods are basically "wrappers" for the NSOutlineViewDataSource methods
+///---------------------------------------------------------------------------------------
+/// @name Supporting Object Persistence
+///---------------------------------------------------------------------------------------
+/**
+ @brief Invoked by *aSourceList* to return the item for the archived *object*.
+ @discussion This method is analagous to `-outlineView:itemForPersistentObject:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message
+ @param object The archived representation of the item in the Source List's data source
+
+ @return The unarchived item corresponding to *object*.
+
+ @see sourceList:persistentObjectForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (id)sourceList:(PXSourceList*)aSourceList itemForPersistentObject:(id)object;
+
+/**
+ @brief Invoked by *aSourceList* to return an archived object for *item*.
+ @discussion This method is analagous to `-outlineView:persistentObjectForItem:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The unarchived item corresponding to *object*.
+
+ @see sourceList:persistentObjectForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (id)sourceList:(PXSourceList*)aSourceList persistentObjectForItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Supporting Drag and Drop
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value indicating whether a drag operation is allowed.
+ @discussion This method is analagous to `-outlineView:writeItems:toPasteboard:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param items An array of items that are participating in the drag.
+ @param pboard The pasteboard to which to write the drag data.
+
+ @return `YES` if the drag should be allowed and the items were successfully written to the pasteboard, or `NO` otherwise.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard;
+
+/**
+ @brief Used by a Source List to determine a valid drop target.
+ @discussion This method is analagous to `-outlineView:validateDrop:proposedItem:proposedChildIndex:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param sourceList The Source List that sent the message.
+ @param info An object which contains more information about the dragging operation.
+ @param item The proposed parent item.
+ @param index The proposed child index of the parent.
+
+ @return An `NSDragOperation` value that indicates which dragging operation the Source List should perform.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSDragOperation)sourceList:(PXSourceList*)sourceList validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index;
+
+/**
+ @brief Returns a Boolean value specifying whether a drag operation was successful.
+ @discussion This method is analagous to `-outlineView:acceptDrop:item:childIndex:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param info An object that contains more information about the dragging operation.
+ @param item The parent of the item which the cursor was over when the mouse button was released.
+ @param index The index of the child of `item` which the cursor was over when the mouse button was released.
+
+ @return `YES` if the drop was successful, or `NO` otherwise.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index;
+
+/**
+ @brief Returns an array of filenames (not file paths) for the created files that the receiver promises to create.
+ @discussion This method is analagous to `-outlineView:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param dropDestination The drop location where the files are created.
+ @param items The items that are being dragged.
+
+ @return An array of filenames (not file paths) for the created files that the receiver promises to create.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSArray *)sourceList:(PXSourceList*)aSourceList namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedItems:(NSArray *)items;
+
+///---------------------------------------------------------------------------------------
+/// @name Drag and drop methods for 10.7+
+///---------------------------------------------------------------------------------------
+
+/**
+ @brief Invoked to allow the Source List to support multiple item dragging.
+ @discussion This method is analagous to `-outlineView:pasteboardWriterForItem:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return Returns an instance of `NSPasteboardItem` or a custom object that implements the `NSPasteboardWriting` protocol. Returning `nil` excludes the item from being dragged.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.7 SDK or above.
+ */
+- (id <NSPasteboardWriting>)sourceList:(PXSourceList *)aSourceList pasteboardWriterForItem:(id)item;
+
+/**
+ @brief Implement this method know when the given dragging session is about to begin and potentially modify the dragging session.
+ @discussion This method is analagous to `-outlineView:draggingSession:willBeginAtPoint:forItems:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List in which the drag is about to begin.
+ @param session The dragging session that is about to begin.
+ @param screenPoint The point onscreen at which the drag is to begin.
+ @param draggedItems An array of items to be dragged, excluding items for which `sourceList:pasteboardWriterForItem:` returns `nil`.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.7 SDK or above.
+ */
+- (void)sourceList:(PXSourceList *)aSourceList draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint forItems:(NSArray *)draggedItems;
+
+/**
+ @brief Implement this method to know when the given dragging session has ended.
+ @discussion This method is analagous to `-outlineView:draggingSession:endedAtPoint:operation:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List in which the drag ended.
+ @param session The dragging session that ended.
+ @param screenPoint The point onscreen at which the drag ended.
+ @param operation A mask specifying the types of drag operations permitted by the dragging source.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.7 SDK or above.
+ */
+- (void)sourceList:(PXSourceList *)aSourceList draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation;
+
+/**
+ @brief Implement this method to enable the Source List to update dragging items as they are dragged over the view.
+ @discussion This method is analagous to `-outlineView:updateDraggingItemsForDrag:` declared on `NSOutlineViewDataSource`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List in which the drag occurs.
+ @param draggingInfo The dragging info object.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.7 SDK or above.
+ */
+- (void)sourceList:(PXSourceList *)aSourceList updateDraggingItemsForDrag:(id <NSDraggingInfo>)draggingInfo;
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListDelegate.h b/modules/gui/macosx/PXSourceList/PXSourceListDelegate.h
new file mode 100755
index 0000000000..7a3b8113e8
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListDelegate.h
@@ -0,0 +1,522 @@
+//
+// PXSourceListDelegate.h
+// PXViewKit
+//
+// Created by Alex Rozanski on 17/10/2009.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Cocoa/Cocoa.h>
+
+ at class PXSourceList;
+
+/**
+ The `PXSourceListDelegate` protocol defines methods that can be implemented by delegates of `PXSourceList` objects.
+
+ Note that additional documentation for the `PXSourceList` delegate notification constants is included in `PXSourceListDelegate.h`. This includes documentation for:
+
+ - `PXSLSelectionIsChangingNotification`
+ - `PXSLSelectionDidChangeNotification`
+ - `PXSLItemWillExpandNotification`
+ - `PXSLItemDidExpandNotification`
+ - `PXSLItemWillCollapseNotification`
+ - `PXSLItemDidCollapseNotification`
+ - `PXSLDeleteKeyPressedOnRowsNotification`
+
+ @warning Most of the methods defined by this protocol are analagous to those declared by `NSOutlineViewDelegate` (and are marked as such in the member's documentation), but are prefixed by "sourceList:" instead of "outlineView:". Only the most basic information about these methods is included here, and you should refer to the `NSOutlineViewDelegate` protocol documentation for more information. Several methods differ to those declared on `NSOutlineViewDelegate` in that they don't have an `NSTableColumn` parameter since `PXSourceList` works implicitly with only one table column.
+ */
+ at protocol PXSourceListDelegate <NSObject>
+
+ at optional
+///---------------------------------------------------------------------------------------
+/// @name Working with Groups
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value that indicates whether a particular group item is displayed as always expanded.
+ @discussion A group that is displayed as *always expanded* displays no 'Show'/'Hide' button to the right on hover, and its direct children are always expanded.
+
+ @param aSourceList The Source List that sent the message.
+ @param group A group item in the data source.
+
+ @return `YES` to specify that the group should be displayed as always expanded, or `NO` if not.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group;
+
+///---------------------------------------------------------------------------------------
+/// @name Handling Mouse and Keyboard Input
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a context menu which is to be displayed for a given mouse-down event.
+ @discussion See `-menuForEvent:` declared on `NSView` for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param theEvent A mouse event.
+ @param item An item in the data source.
+
+ @return An instantiated `NSMenu` object to be displayed by the Source List for *event*, or `nil` if no menu is to be shown for the given event.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item;
+
+/**
+ @brief Invoked when *notification* is posted (when a deletion key is pressed and a row in the Source List is selected).
+ @discussion This method is invoked when the `PXSLDeleteKeyPressedOnRowsNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ @param notification The posted notification.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListDeleteKeyPressedOnRows:(NSNotification *)notification;
+
+// The following methods are basically wrappers around NSOutlineViewDelegate methods.
+
+///---------------------------------------------------------------------------------------
+/// @name View-based Source List Delegate Methods
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the view used to display the given item.
+ @discussion This method is analagous to `-outlineView:viewForTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:viewForTableColumn:item:` for more information.
+
+ Unlike when using `PXSourceList` in cell-based mode where the icon and badge value for each item can be set up using `PXSourceListDataSource` methods, it is in this method that you should set up the icon and badge for the view (if applicable) when using `PXSourceList` in view-based mode. You can make use of the `PXSourceListTableCellView` class which exposes an outlet for a `PXSourceListBadgeView` (the class included with the project used to display badges), and the `textField` and `imageView` outlets (which are inherited from its superclass, `NSTableCellView`) for the item's label and icon, respectively.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The view to display for the specified item, or `nil` if you don't want to display a view for the item.
+
+ @warning This is a required method when using the Source List in view-based mode.
+
+ @see sourceList:rowViewForItem:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (NSView *)sourceList:(PXSourceList *)aSourceList viewForItem:(id)item;
+
+/**
+ @brief Returns the view used to display the given row.
+ @discussion This method is analagous to `-outlineView:rowViewForItem:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return An `NSTableRowView` instance, or `nil` if the Source List should create one and use that instead.
+
+ @see sourceList:viewForItem:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (NSTableRowView *)sourceList:(PXSourceList *)aSourceList rowViewForItem:(id)item;
+
+/**
+ @brief Sent when a row view has been added to the Source List.
+ @discussion This method is analagous to `-outlineView:didAddRowView:forRow:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param rowView The view that was added to the Source List.
+ @param row The row index.
+
+ @see sourceList:didRemoveRowView:forRow:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (void)sourceList:(PXSourceList *)aSourceList didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row;
+
+/**
+ @brief Sent when a row view has been removed from the Source List.
+ @discussion This method is analagous to `-outlineView:didRemoveRowView:forRow:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param rowView The row view that was removed from the Source List.
+ @param row The row index.
+
+ @see sourceList:didAddRowView:forRow:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (void)sourceList:(PXSourceList *)aSourceList didRemoveRowView:(NSTableRowView *)rowView forRow:(NSInteger)row;
+
+///---------------------------------------------------------------------------------------
+/// @name Handling Selection
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value indicating whether a given item should be selected.
+ @discussion This method is analagous to `-outlineView:shouldSelectItem:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` to allow the Source List to select *item*, or `NO` otherwise.
+
+ @see sourceList:selectionIndexesForProposedSelection:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList shouldSelectItem:(id)item;
+
+/**
+ @brief Returns the indexes that should be selected for a user-initiated selection.
+ @discussion This method is analagous to `-outlineView:selectionIndexesForProposedSelection:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param proposedSelectionIndexes The proposed indexes of rows that should be selected.
+
+ @return An `NSIndexSet` object containing the rows that should be selected in the proposed selection.
+
+ @see sourceList:shouldSelectItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSIndexSet*)sourceList:(PXSourceList*)aSourceList selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes;
+
+/**
+ @brief Invoked when *notification* is posted (when the Source List's selection changes).
+ @discussion This method is invoked when the `PXSLSelectionIsChangingNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ This method is analagous to `-outlineViewSelectionIsChanging:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param notification The posted notification.
+
+ @see sourceListSelectionDidChange:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListSelectionIsChanging:(NSNotification *)notification;
+
+/**
+ @brief Invoked when *notification* is posted (when the Source List's selection has finished changing).
+ @discussion This method is invoked when the `PXSLSelectionDidChangeNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ This method is analagous to `-outlineViewSelectionDidChange:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param notification The posted notification.
+
+ @see sourceListSelectionIsChanging:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListSelectionDidChange:(NSNotification *)notification;
+
+///---------------------------------------------------------------------------------------
+/// @name Working with Type Selection
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the string that is used for type selection for a given item.
+ @discussion This method is analagous to `-outlineView:typeSelectStringForTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:typeSelectStringForTableColumn:item:` for more information.
+
+ @param sourceList The Source List that sent the message.
+ @param item The item to generate the type selection string for.
+
+ @return The string value used for type selection of *item*.
+
+ @see sourceList:nextTypeSelectMatchFromItem:toItem:forString:
+ @see sourceList:shouldTypeSelectForEvent:withCurrentSearchString:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (NSString *)sourceList:(PXSourceList *)sourceList typeSelectStringForItem:(id)item;
+
+/**
+ @brief Returns the first item that matches the given search string from within the given range.
+ @discussion This method is analagous to `-outlineView:nextTypeSelectMatchFromItem:toItem:forString:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param sourceList The Source List that sent the message.
+ @param startItem The first item to search.
+ @param endItem The item before which to stop searching.
+ @param searchString The string to search.
+
+ @return The first item in the *startItem*--*endItem* range which matches *searchString*, or `nil` if there is no match.
+
+ @see sourceList:typeSelectStringForItem:
+ @see sourceList:shouldTypeSelectForEvent:withCurrentSearchString:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (id)sourceList:(PXSourceList *)sourceList nextTypeSelectMatchFromItem:(id)startItem toItem:(id)endItem forString:(NSString *)searchString;
+
+/**
+ @brief Returns a Boolean value which indicates whether type select should proceed for a given event and search string.
+ @discussion This method is analagous to `-outlineView:shouldTypeSelectForEvent:withCurrentSearchString:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param sourceList The Source List that sent the message.
+ @param event The event that caused this message to be sent.
+ @param searchString The search string for which searching is to proceed from.
+
+ @return `YES` if type select should proceed, or `NO` otherwise.
+
+ @see sourceList:typeSelectStringForItem:
+ @see sourceList:nextTypeSelectMatchFromItem:toItem:forString:
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList *)sourceList shouldTypeSelectForEvent:(NSEvent *)event withCurrentSearchString:(NSString *)searchString;
+
+/**
+ @brief Returns a Boolean value which indicates whether a cell expansion tooltip should be displayed for a given item.
+ @discussion This method is analagous to `-outlineView:shouldShowCellExpansionForTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:shouldShowCellExpansionForItem:` for more information.
+
+ @param sourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` to allow an expansion tooltip to be displayed for *item*, otherwise `NO`.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, this method is not called.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList *)sourceList shouldShowCellExpansionForItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Providing Tooltips
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the tooltip string that should be displayed for a given cell.
+ @discussion This method is analagous to `-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:` for more information.
+
+ @param sourceList The Source List that sent the message.
+ @param cell The cell to return the tooltip for.
+ @param rect The proposed active area of the tooltip.
+ @param item The item in the data source to display the tooltip for.
+ @param mouseLocation The current mouse location in view coordinates.
+
+ @return The tooltip string to be displayed for *cell*, or `nil` if no tooltip is to be shown.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, this method is not called.
+
+ @since Requires PXSourceList 2.0.0 or above and the OS X v10.7 SDK or above.
+ */
+- (NSString *)sourceList:(PXSourceList *)sourceList toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect item:(id)item mouseLocation:(NSPoint)mouseLocation;
+
+///---------------------------------------------------------------------------------------
+/// @name Editing Items
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value which indicates whether the Source List should allow editing of a given item.
+ @discussion This method is analagous to `-outlineView:shouldEditTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:shouldEditTableColumn:item:` for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` to allow editing of *item*, or `NO` otherwise.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList shouldEditItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Customising Tracking Support
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value that indicates whether a given cell should be tracked
+ @discussion This method is analagous to `-outlineView:shouldTrackCell:forTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:shouldTrackCell:forTableColumn:item:` for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param cell The cell used to display *item*.
+ @param item An item in the data source.
+
+ @return `YES` if the cell should be tracked for *item*, otherwise `NO`.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, this method is not called.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList shouldTrackCell:(NSCell *)cell forItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Expanding and Collapsing the Outline
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns a Boolean value that indicates whether a given item should be expanded.
+ @discussion This method is analagous to `-outlineView:shouldExpandItem:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` to allow expansion of *item*, otherwise `NO`.
+
+ @see sourceListItemWillExpand:
+ @see sourceListItemDidExpand:
+ @see sourceList:shouldCollapseItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList shouldExpandItem:(id)item;
+
+/**
+ @brief Returns a Boolean value that indicates whether a given item should be collapsed.
+ @discussion This method is analagous to `-outlineView:shouldCollapseItem:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return `YES` to allow *item* to be collapsed, otherwise `NO`.
+
+ @see sourceListItemWillCollapse:
+ @see sourceListItemDidCollapse:
+ @see sourceList:shouldExpandItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (BOOL)sourceList:(PXSourceList*)aSourceList shouldCollapseItem:(id)item;
+
+/**
+ @brief Invoked when *notification* is posted (when an item in the Source List is about to expand in response to user input).
+ @discussion This method is invoked when the `PXSLItemWillExpandNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ This method is analagous to `-outlineViewItemWillExpand:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param notification The posted notification.
+
+ @see sourceListItemDidExpand:
+ @see sourceList:shouldExpandItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListItemWillExpand:(NSNotification *)notification;
+
+/**
+ @brief Invoked when *notification* is posted (when an item in the Source List was expanded in response to user input).
+ @discussion This method is invoked when the `PXSLItemDidExpandNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ This method is analagous to `-outlineViewItemDidExpand:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param notification The posted notification.
+
+ @see sourceListItemWillExpand:
+ @see sourceList:shouldExpandItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListItemDidExpand:(NSNotification *)notification;
+
+/**
+ @brief Invoked when *notification* is posted (when an item in the Source List is about to collapse in response to user input).
+ @discussion This method is invoked when the `PXSLItemWillCollapseNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ This method is analagous to `-outlineViewItemWillCollapse:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param notification The posted notification.
+
+ @see sourceListItemDidCollapse:
+ @see sourceList:shouldCollapseItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListItemWillCollapse:(NSNotification *)notification;
+
+/**
+ @brief Invoked when *notification* is posted (when an item in the Source List was collapsed in response to user input).
+ @discussion This method is invoked when the `PXSLItemDidCollapseNotification` notification is posted. See `PXSourceListDelegate.h` for documentation for this notification constant.
+
+ This method is analagous to `-outlineViewItemDidCollapse:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param notification The posted notification.
+
+ @see sourceListItemWillCollapse:
+ @see sourceList:shouldCollapseItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceListItemDidCollapse:(NSNotification *)notification;
+
+///---------------------------------------------------------------------------------------
+/// @name Customising Row Sizes
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the height in points of the row for the given item.
+ @discussion This method is analagous to `-outlineView:heightOfRowByItem:` declared on `NSOutlineViewDelegate`. See the documentation for this method for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The height of the row used to display *item* in points.
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (CGFloat)sourceList:(PXSourceList*)aSourceList heightOfRowByItem:(id)item;
+
+///---------------------------------------------------------------------------------------
+/// @name Displaying Cells
+///---------------------------------------------------------------------------------------
+
+/**
+ @brief Informs the delegate that the Source List is about to display the cell associated with the given item.
+ @discussion This method is analagous to `-outlineView:willDisplayCell:forTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:willDisplayCell:forTableColumn:item:` for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param cell The cell about to be displayed.
+ @param item An item in the data source.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, this method is not called.
+
+ @see sourceList:dataCellForItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (void)sourceList:(PXSourceList*)aSourceList willDisplayCell:(id)cell forItem:(id)item;
+
+/**
+ @brief Returns the cell for use with a given item in the Source List.
+ @discussion This method is analagous to `-outlineView:dataCellForTableColumn:item:` declared on `NSOutlineViewDelegate`, although it doesn't pass an `NSTableColumn` parameter as `PXSourceList` implicitly only uses one table column. See the documentation for `-outlineView:dataCellForTableColumn:item:` for more information.
+
+ @param aSourceList The Source List that sent the message.
+ @param item An item in the data source.
+
+ @return The cell used to display *item*.
+
+ @warning This method is only used by the Source List when operating in cell-based mode. When the Source List is operating in view-based mode, this method is not called.
+
+ @see sourceList:willDisplayCell:forItem:
+
+ @since Requires PXSourceList 0.8 or above and the OS X v10.5 SDK or above.
+ */
+- (NSCell*)sourceList:(PXSourceList*)aSourceList dataCellForItem:(id)item;
+
+ at end
+
+//PXSourceList delegate notifications
+/**
+ @brief This is analagous to the `NSOutlineViewSelectionIsChangingNotification` notification. Take a look at the `NSOutlineView` documentation for more information.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLSelectionIsChangingNotification;
+
+/**
+ @brief This is analagous to the `NSOutlineViewSelectionDidChangeNotification` notification. Take a look at the `NSOutlineView` documentation for more information.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLSelectionDidChangeNotification;
+
+/**
+ @brief This is analagous to the `NSOutlineViewItemWillExpandNotification` notification. Take a look at the `NSOutlineView` documentation for more information.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLItemWillExpandNotification;
+
+/**
+ @brief This is analagous to the `NSOutlineViewItemDidExpandNotification` notification. Take a look at the `NSOutlineView` documentation for more information.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLItemDidExpandNotification;
+
+/**
+ @brief This is analagous to the `NSOutlineViewItemWillCollapseNotification` notification. Take a look at the `NSOutlineView` documentation for more information.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLItemWillCollapseNotification;
+
+/**
+ @brief This is analagous to the `NSOutlineViewItemDidCollapseNotification` notification. Take a look at the `NSOutlineView` documentation for more information.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLItemDidCollapseNotification;
+
+/**
+ @brief Posted whenever a "deletion key" (backspace, cmd-backspace or fn-backspace) is pressed and handled by the Source List and a row is selected.
+ @discussion The notification *object* is the `PXSourceList` object which the notification was posted by. The *userInfo* dictionary contains a `@"rows"` key which maps to an `NSIndexSet` object which contains the selected row indexes that were selected when the notification was posted.
+ @since Requires PXSourceList 0.8 or above.
+ */
+extern NSString * const PXSLDeleteKeyPressedOnRowsNotification;
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListItem.h b/modules/gui/macosx/PXSourceList/PXSourceListItem.h
new file mode 100755
index 0000000000..fc55a392b4
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListItem.h
@@ -0,0 +1,228 @@
+//
+// PXSourceListItem.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 08/01/2014.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+
+ `PXSourceListItem` is a generic `NSObject` subclass which can be used to build a hierarchical model for use by
+ a `PXSourceList` data source.
+
+ @warning While it is not mandatory to use `PXSourceListItem` objects in a `PXSourceList` data source, this
+ class is generic enough that it should serve most use cases.
+
+ @discussion ### Basic properties
+
+ `PXSourceListItem` has been designed to contain properties for the frequently-used information which you need
+ from a Source List data source item when implementing the `PXSourceListDataSource` (and possibly
+ `PXSourceListDelegate`) methods, namely:
+
+ * The title displayed in the Source List for the given item.
+ * The icon displayed to the left of the given item in the Source List.
+ * The badge value displayed to the right of the given item in the Source List.
+ * Child items of the given item.
+
+ The existence of these core properties means that it is unlikely that you should have to create your own
+ `PXSourceListItem` subclass.
+
+ ### Identifying objects
+
+ `PXSourceListItem`s are often backed by data model objects that are used in other parts of your application, and
+ the API has been designed to be able to easily identify a given model object from any part of your code
+ given an arbitrary `PXSourceListItem`. This is useful when you obtain an item using one of `PXSourceList`'s methods
+ or are given one as an argument to a `PXSourceListDelegate` or `PXSourceListDataSource` protocol method and you
+ need to find its backing data model object to be able to use in application logic.
+
+ There are two (often distinct) patterns used to identify a given backing model object in a `PXSourceListItem`
+ object:
+
+ * Using the `identifier` property. This is probably the easiest way of identifying items, and these identifiers
+ are best defined as string constants which you can reference from multiple places in your code.
+ * Using the `representedObject` property. Using `representedObject` can be useful if the underlying model
+ object has identifying information about it which you can use when determining which object you're
+ working with given a `PXSourceListItem` instance.
+
+ */
+ at interface PXSourceListItem : NSObject
+
+ at property (strong, nonatomic) NSString *title;
+ at property (strong, nonatomic) NSImage *icon;
+ at property (weak, nonatomic) id representedObject;
+ at property (strong, nonatomic) NSString *identifier;
+ at property (strong, nonatomic) NSNumber *badgeValue;
+
+///---------------------------------------------------------------------------------------
+/// @name Convenience initialisers
+///---------------------------------------------------------------------------------------
+/** Creates and returns an item with the given parameters.
+
+ @param title A title.
+ @param identifier An identifier.
+
+ @return An item initialised with the given parameters.
+
+ @see itemWithTitle:identifier:icon:
+ @see itemWithRepresentedObject:icon:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
++ (instancetype)itemWithTitle:(NSString *)title identifier:(NSString *)identifier;
+
+/** Creates and returns an item with the given parameters.
+
+ @param title A title.
+ @param identifier An identifier.
+ @param icon An icon.
+
+ @return An item initialised with the given parameters.
+
+ @see itemWithTitle:identifier:
+ @see itemWithRepresentedObject:icon:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
++ (instancetype)itemWithTitle:(NSString *)title identifier:(NSString *)identifier icon:(NSImage *)icon;
+
+/** Creates and returns an item with the given parameters.
+
+ @param object An object.
+ @param icon An icon.
+
+ @return An item initialised with the given parameters.
+
+ @see itemWithTitle:identifier:
+ @see itemWithTitle:identifier:icon:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
++ (instancetype)itemWithRepresentedObject:(id)object icon:(NSImage *)icon;
+
+///---------------------------------------------------------------------------------------
+/// @name Working with child items
+///---------------------------------------------------------------------------------------
+/**
+ @brief Returns the receiver's children.
+
+ @warning This property is backed by an `NSMutableArray` since an item's children *are* mutable. The getter for
+ this property returns a copied array for safety, so this getter should not be called excessively.
+
+ @see hasChildren
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+ at property (strong, nonatomic) NSArray *children;
+
+/**
+ @brief Returns whether the receiver has any child items.
+ @discussion This is faster than calling `-children` on the receiver then checking the number of items in the array
+ because of how this getter is implemented. See `-children` for more information.
+
+ @see children
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (BOOL)hasChildren;
+
+/**
+ @brief Adds an item to the receiver's array of child items.
+ @discussion Adds *item* to the end of the receiver's array of child items.
+
+ This is a convenience method rather than having to call `-children` on the receiver, create a mutable copy
+ and then mutate this array before setting it back on the receiver.
+
+ @param childItem An item
+
+ @see insertChildItem:atIndex:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (void)addChildItem:(PXSourceListItem *)childItem;
+
+/**
+ @brief Inserts an item to the receiver's array of child items at a given index.
+ @discussion Inserts *item* at *index* in the receiver's array of child items.
+
+ This is a convenience method rather than having to call `-children` on the receiver, create a mutable copy
+ and then mutate this array before setting it back on the receiver.
+
+ @param childItem An item
+ @param index An index
+
+ @see addChildItem:
+ @see insertChildItems:atIndexes:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (void)insertChildItem:(PXSourceListItem *)childItem atIndex:(NSUInteger)index;
+
+/**
+ @brief Removes an item from the receiver's array of child items.
+ @discussion Removes *item* from the receiver's array of child items.
+
+ This is a convenience method rather than having to call `-children` on the receiver, create a mutable copy
+ and then mutate this array before setting it back on the receiver.
+
+ @param childItem An item
+
+ @see removeChildItemAtIndex:
+ @see removeChildItems:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (void)removeChildItem:(PXSourceListItem *)childItem;
+
+/**
+ @brief Removes the item at the given index from the receiver's array of child items.
+ @discussion Removes the item at the given *index* from the receiver's array of child items.
+
+ This is a convenience method rather than having to call `-children` on the receiver, create a mutable copy
+ and then mutate this array before setting it back on the receiver.
+
+ @param index An integer representing an index in the receiver's array of children
+
+ @see removeChildItem:
+ @see removeChildItems:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (void)removeChildItemAtIndex:(NSUInteger)index;
+
+/**
+ @brief Removes the items in the given array from the receiver's array of child items.
+ @discussion Removes all of the items in *items* from the receiver's array of children.
+
+ This is a convenience method rather than having to call `-children` on the receiver, create a mutable copy
+ and then mutate this array before setting it back on the receiver.
+
+ @param items An array of `PXSourceListItem` objects
+
+ @see removeChildItem:
+ @see removeChildItemAtIndex:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (void)removeChildItems:(NSArray *)items;
+
+/**
+ @brief Inserts the given items into the receiver's array of child items at the given indexes.
+ @discussion Inserts all of the items in *items* to the receiver's array of children at the given *indexes*.
+
+ This is a convenience method rather than having to call `-children` on the receiver, create a mutable copy
+ and then mutate this array before setting it back on the receiver.
+
+ @param items An array of `PXSourceListItem` objects
+ @param indexes The indexes to insert the child items at
+
+ @see insertChildItem:atIndex:
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+- (void)insertChildItems:(NSArray *)items atIndexes:(NSIndexSet *)indexes;
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListItem.m b/modules/gui/macosx/PXSourceList/PXSourceListItem.m
new file mode 100755
index 0000000000..5841e14923
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListItem.m
@@ -0,0 +1,101 @@
+//
+// PXSourceListItem.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 08/01/2014.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceListItem.h"
+
+ at implementation PXSourceListItem {
+ NSMutableArray *_children;
+}
+
++ (instancetype)itemWithTitle:(NSString *)title identifier:(NSString *)identifier
+{
+ return [self itemWithTitle:title identifier:identifier icon:nil];
+}
+
++ (instancetype)itemWithTitle:(NSString *)title identifier:(NSString *)identifier icon:(NSImage *)icon
+{
+ PXSourceListItem *item = [[self alloc] init];
+
+ item.title = title;
+ item.identifier = identifier;
+ item.icon = icon;
+
+ return item;
+}
+
++ (instancetype)itemWithRepresentedObject:(id)object icon:(NSImage *)icon
+{
+ PXSourceListItem *item = [[self alloc] init];
+
+ item.representedObject = object;
+ item.icon = icon;
+
+ return item;
+}
+
+- (id)init
+{
+ if (!(self = [super init]))
+ return nil;
+
+ _children = [[NSMutableArray alloc] init];
+
+ return self;
+}
+
+#pragma mark - Custom Accessors
+
+- (NSArray *)children
+{
+ return [_children copy];
+}
+
+- (void)setChildren:(NSArray *)children
+{
+ _children = [children mutableCopy];
+}
+
+#pragma mark - Child Convenience Methods
+
+- (BOOL)hasChildren
+{
+ return _children.count > 0;
+}
+
+- (void)addChildItem:(PXSourceListItem *)childItem
+{
+ [_children addObject:childItem];
+}
+
+- (void)insertChildItem:(PXSourceListItem *)childItem atIndex:(NSUInteger)index
+{
+ [_children insertObject:childItem atIndex:index];
+}
+
+- (void)removeChildItem:(PXSourceListItem *)childItem
+{
+ [_children removeObject:childItem];
+}
+
+- (void)removeChildItemAtIndex:(NSUInteger)index
+{
+ [_children removeObjectAtIndex:index];
+}
+
+- (void)removeChildItems:(NSArray *)items
+{
+ [_children removeObjectsInArray:items];
+}
+
+- (void)insertChildItems:(NSArray *)items atIndexes:(NSIndexSet *)indexes
+{
+ [_children insertObjects:items atIndexes:indexes];
+}
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListTableCellView.h b/modules/gui/macosx/PXSourceList/PXSourceListTableCellView.h
new file mode 100755
index 0000000000..50023d6203
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListTableCellView.h
@@ -0,0 +1,43 @@
+//
+// PXSourceListTableCellView.h
+// PXSourceList
+//
+// Created by Alex Rozanski on 31/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import <Cocoa/Cocoa.h>
+
+ at class PXSourceListBadgeView;
+
+/**
+ `PXSourceListTableCellView` is an `NSTableCellView` subclass which can be used when using `PXSourceList`
+ in view-based mode.
+
+ Similar to `NSTableCellView` and its `textField` and `imageView` outlets, `PXSourceListTableCellView`
+ provides a `badgeView` outlet which can be hooked up to a `PXSourceListBadgeView` in Interface Builder
+ and then configured in `sourceList:viewForItem:`.
+
+ `PXSourceListTableCellView` positions its `badgeView` automatically (as `NSTableCellView` does for the `textField`
+ and `imageView` outlets) to be positioned centred (vertically) and rightmost (horizontally) within the table cell's
+ bounds. If you want to change this positioning you can do so by creating a `PXSourceListTableCellView` subclass and
+ overriding `-layout`, but note that idiomatically, source lists display badges to the right of each row.
+ */
+ at interface PXSourceListTableCellView : NSTableCellView
+
+/**
+ @brief The badge view displayed by the cell.
+ @discussion When a `PXSourceListTableCellView` instance is created, a `PXSourceListTableCellView` instance
+ is *not* automatically created and set to this property (just like with `NSTableCellView` and its
+ `textField` and `imageView` properties). This property is purely declared on this class to make creating
+ table cell views for a `PXSourceList` in Interface Builder easier without having to declare your own
+ `NSTableCellView` subclass.
+
+ This property is typically configured in the `PXSourceListDelegate` method `sourceList:viewForItem:`.
+
+ @since Requires PXSourceList 2.0.0 and above and the Mac OS X 10.7 SDK or above.
+ */
+ at property (weak, nonatomic) IBOutlet PXSourceListBadgeView *badgeView;
+
+ at end
diff --git a/modules/gui/macosx/PXSourceList/PXSourceListTableCellView.m b/modules/gui/macosx/PXSourceList/PXSourceListTableCellView.m
new file mode 100755
index 0000000000..e887d0bb5f
--- /dev/null
+++ b/modules/gui/macosx/PXSourceList/PXSourceListTableCellView.m
@@ -0,0 +1,31 @@
+//
+// PXSourceListTableCellView.m
+// PXSourceList
+//
+// Created by Alex Rozanski on 31/12/2013.
+// Copyright 2009-14 Alex Rozanski http://alexrozanski.com and other contributors.
+// This software is licensed under the New BSD License. Full details can be found in the README.
+//
+
+#import "PXSourceListTableCellView.h"
+#import "PXSourceListBadgeView.h"
+
+ at implementation PXSourceListTableCellView
+
+- (void)layout
+{
+ [super layout];
+
+ if (!self.badgeView)
+ return;
+
+ [self.badgeView sizeToFit];
+
+ NSRect bounds = self.bounds;
+ NSSize badgeSize = self.badgeView.frame.size;
+ self.badgeView.frame = NSMakeRect(NSMaxX(bounds) - badgeSize.width,
+ NSMidY(bounds) - round(badgeSize.height / 2.0f),
+ badgeSize.width, badgeSize.height);
+}
+
+ at end
diff --git a/modules/gui/macosx/PXSourceListDataSource.h b/modules/gui/macosx/PXSourceListDataSource.h
deleted file mode 100644
index 88e19cd335..0000000000
--- a/modules/gui/macosx/PXSourceListDataSource.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// PXSourceListDataSource.h
-// PXViewKit
-//
-// Created by Alex Rozanski on 17/10/2009.
-// Copyright 2009-10 Alex Rozanski http://perspx.com
-//
-
-#import <Cocoa/Cocoa.h>
-
- at class PXSourceList;
-
- at protocol PXSourceListDataSource <NSObject>
-
- at required
-- (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item;
-- (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item;
-- (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item;
-- (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item;
-
- at optional
-- (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item;
-
-- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item;
-- (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item;
-- (NSColor*)sourceList:(PXSourceList*)aSourceList badgeTextColorForItem:(id)item;
-- (NSColor*)sourceList:(PXSourceList*)aSourceList badgeBackgroundColorForItem:(id)item;
-
-- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item;
-- (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item;
-
-//The rest of these methods are basically "wrappers" for the NSOutlineViewDataSource methods
-- (id)sourceList:(PXSourceList*)aSourceList itemForPersistentObject:(id)object;
-- (id)sourceList:(PXSourceList*)aSourceList persistentObjectForItem:(id)item;
-
-- (BOOL)sourceList:(PXSourceList*)aSourceList writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard;
-- (NSDragOperation)sourceList:(PXSourceList*)sourceList validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index;
-- (BOOL)sourceList:(PXSourceList*)aSourceList acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index;
-- (NSArray *)sourceList:(PXSourceList*)aSourceList namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedItems:(NSArray *)items;
-
- at end
diff --git a/modules/gui/macosx/PXSourceListDelegate.h b/modules/gui/macosx/PXSourceListDelegate.h
deleted file mode 100644
index 1651ea79d8..0000000000
--- a/modules/gui/macosx/PXSourceListDelegate.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// PXSourceListDelegate.h
-// PXViewKit
-//
-// Created by Alex Rozanski on 17/10/2009.
-// Copyright 2009-10 Alex Rozanski http://perspx.com
-//
-
-#import <Cocoa/Cocoa.h>
-
- at class PXSourceList;
-
- at protocol PXSourceListDelegate <NSObject>
-
- at optional
-//Extra methods
-- (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group;
-- (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item;
-
-//Basically NSOutlineViewDelegate wrapper methods
-- (BOOL)sourceList:(PXSourceList*)aSourceList shouldSelectItem:(id)item;
-- (NSIndexSet*)sourceList:(PXSourceList*)aSourceList selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes;
-
-- (BOOL)sourceList:(PXSourceList*)aSourceList shouldEditItem:(id)item;
-
-- (BOOL)sourceList:(PXSourceList*)aSourceList shouldTrackCell:(NSCell *)cell forItem:(id)item;
-
-- (BOOL)sourceList:(PXSourceList*)aSourceList shouldExpandItem:(id)item;
-- (BOOL)sourceList:(PXSourceList*)aSourceList shouldCollapseItem:(id)item;
-
-- (CGFloat)sourceList:(PXSourceList*)aSourceList heightOfRowByItem:(id)item;
-
-- (NSCell*)sourceList:(PXSourceList*)aSourceList willDisplayCell:(id)cell forItem:(id)item;
-- (NSCell*)sourceList:(PXSourceList*)aSourceList dataCellForItem:(id)item;
-
- at end
-
- at interface NSObject (PXSourceListNotifications)
-
-//Selection
-- (void)sourceListSelectionIsChanging:(NSNotification *)notification;
-- (void)sourceListSelectionDidChange:(NSNotification *)notification;
-
-//Item expanding/collapsing
-- (void)sourceListItemWillExpand:(NSNotification *)notification;
-- (void)sourceListItemDidExpand:(NSNotification *)notification;
-- (void)sourceListItemWillCollapse:(NSNotification *)notification;
-- (void)sourceListItemDidCollapse:(NSNotification *)notification;
-
-- (void)sourceListDeleteKeyPressedOnRows:(NSNotification *)notification;
-
-
- at end
-
-//PXSourceList delegate notifications
-extern NSString * const PXSLSelectionIsChangingNotification;
-extern NSString * const PXSLSelectionDidChangeNotification;
-extern NSString * const PXSLItemWillExpandNotification;
-extern NSString * const PXSLItemDidExpandNotification;
-extern NSString * const PXSLItemWillCollapseNotification;
-extern NSString * const PXSLItemDidCollapseNotification;
-extern NSString * const PXSLDeleteKeyPressedOnRowsNotification;
-
diff --git a/modules/gui/macosx/SideBarItem.h b/modules/gui/macosx/SideBarItem.h
deleted file mode 100644
index 9afae32e38..0000000000
--- a/modules/gui/macosx/SideBarItem.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// SourceListItem.h
-// PXSourceList
-//
-// Created by Alex Rozanski on 08/01/2010.
-// Copyright 2010 Alex Rozanski http://perspx.com
-//
-// Adapted to VLC media player by Felix Paul Kühne
-//
-
-#import <Cocoa/Cocoa.h>
-
-/*An example of a class that could be used to represent a Source List Item
-
- Provides a title, an identifier, and an icon to be shown, as well as a badge value and a property to determine
- whether the current item has a badge or not (`badgeValue` is set to -1 if no badge is shown)
-
- Used to form a hierarchical model of SourceListItem instances – similar to the Source List tree structure
- and easily accessible by the data source with the "children" property
-
- SourceListItem *parent
- - SourceListItem *child1;
- - SourceListItem *child2;
- - SourceListItem *childOfChild2;
-
- - SourceListItem *anotherChildOfChild2;
- - SourceListItem *child3;
-
- */
-
- at interface SideBarItem : NSObject
-
- at property (nonatomic, copy) NSString *title;
- at property (nonatomic, copy) NSString *identifier;
- at property (nonatomic, retain) NSImage *icon;
- at property NSInteger badgeValue;
- at property NSInteger sdtype;
-
- at property (nonatomic, copy) NSArray *children;
-
-//Convenience methods
-+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier;
-+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier icon:(NSImage*)anIcon;
-
-
-- (BOOL)hasBadge;
-- (BOOL)hasChildren;
-- (BOOL)hasIcon;
-
- at end
diff --git a/modules/gui/macosx/SideBarItem.m b/modules/gui/macosx/SideBarItem.m
deleted file mode 100644
index 480b14ef39..0000000000
--- a/modules/gui/macosx/SideBarItem.m
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// SideBarItem.m
-// PXSourceList
-//
-// Created by Alex Rozanski on 08/01/2010.
-// Copyright 2010 Alex Rozanski http://perspx.com
-//
-// GC-enabled code revised by Stefan Vogt http://byteproject.net
-//
-// Adapted to VLC media player by Felix Paul Kühne
-
-
-#import "SideBarItem.h"
-
-
- at implementation SideBarItem
-
-#pragma mark -
-#pragma mark Init/Dealloc/Finalize
-
-- (id)init
-{
- if (self=[super init]) {
- _badgeValue = -1; //We don't want a badge value by default
- _sdtype = -1; //no sd type set
- }
-
- return self;
-}
-
-
-+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier
-{
- SideBarItem *item = [SideBarItem itemWithTitle:aTitle identifier:anIdentifier icon:nil];
-
- return item;
-}
-
-
-+ (id)itemWithTitle:(NSString*)aTitle identifier:(NSString*)anIdentifier icon:(NSImage*)anIcon
-{
-
- SideBarItem *item = [[SideBarItem alloc] init];
-
- [item setTitle:aTitle];
- [item setIdentifier:anIdentifier];
- [item setIcon:anIcon];
-
- return item;
-}
-
-#pragma mark -
-#pragma mark Custom Accessors
-
-- (BOOL)hasBadge
-{
- return _badgeValue!=-1;
-}
-
-- (BOOL)hasChildren
-{
- return [_children count]>0;
-}
-
-- (BOOL)hasIcon
-{
- return _icon!=nil;
-}
-
- at end
diff --git a/modules/gui/macosx/VLCMainWindow.m b/modules/gui/macosx/VLCMainWindow.m
index 6190781805..d202460c01 100644
--- a/modules/gui/macosx/VLCMainWindow.m
+++ b/modules/gui/macosx/VLCMainWindow.m
@@ -34,7 +34,7 @@
#import "VLCMainMenu.h"
#import "VLCOpenWindowController.h"
#import "VLCPlaylist.h"
-#import "SideBarItem.h"
+#import "VLCSourceListItem.h"
#import <math.h>
#import <vlc_playlist.h>
#import <vlc_url.h>
@@ -42,8 +42,8 @@
#import <vlc_services_discovery.h>
#import "VLCPLModel.h"
-#import "PXSourceList.h"
-#import "PXSourceListDataSource.h"
+#import "PXSourceList/PXSourceList.h"
+#import "PXSourceList/PXSourceListDataSource.h"
#import "VLCMainWindowControlsBar.h"
#import "VLCVoutView.h"
@@ -315,15 +315,15 @@ - (void)reloadSidebar
}
o_sidebaritems = [[NSMutableArray alloc] init];
- SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
- SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
+ VLCSourceListItem *libraryItem = [VLCSourceListItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
+ VLCSourceListItem *playlistItem = [VLCSourceListItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
[playlistItem setIcon: sidebarImageFromRes(@"sidebar-playlist", darkMode)];
- SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
+ VLCSourceListItem *medialibraryItem = [VLCSourceListItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
[medialibraryItem setIcon: sidebarImageFromRes(@"sidebar-playlist", darkMode)];
- SideBarItem *mycompItem = [SideBarItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
- SideBarItem *devicesItem = [SideBarItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
- SideBarItem *lanItem = [SideBarItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
- SideBarItem *internetItem = [SideBarItem itemWithTitle:_NS("INTERNET") identifier:@"internet"];
+ VLCSourceListItem *mycompItem = [VLCSourceListItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
+ VLCSourceListItem *devicesItem = [VLCSourceListItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
+ VLCSourceListItem *lanItem = [VLCSourceListItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
+ VLCSourceListItem *internetItem = [VLCSourceListItem itemWithTitle:_NS("INTERNET") identifier:@"internet"];
/* SD subnodes, inspired by the Qt intf */
char **ppsz_longnames = NULL;
@@ -342,22 +342,22 @@ - (void)reloadSidebar
o_identifier = toNSStr(*ppsz_name);
switch (*p_category) {
case SD_CAT_INTERNET:
- [internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
+ [internetItems addObject: [VLCSourceListItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
[[internetItems lastObject] setIcon: sidebarImageFromRes(@"sidebar-podcast", darkMode)];
[[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
break;
case SD_CAT_DEVICES:
- [devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
+ [devicesItems addObject: [VLCSourceListItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
[[devicesItems lastObject] setIcon: sidebarImageFromRes(@"sidebar-local", darkMode)];
[[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
break;
case SD_CAT_LAN:
- [lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
+ [lanItems addObject: [VLCSourceListItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
[[lanItems lastObject] setIcon: sidebarImageFromRes(@"sidebar-local", darkMode)];
[[lanItems lastObject] setSdtype: SD_CAT_LAN];
break;
case SD_CAT_MYCOMPUTER:
- [mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
+ [mycompItems addObject: [VLCSourceListItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
if (!strncmp(*ppsz_name, "video_dir", 9))
[[mycompItems lastObject] setIcon: sidebarImageFromRes(@"sidebar-movie", darkMode)];
else if (!strncmp(*ppsz_name, "audio_dir", 9))
@@ -984,7 +984,7 @@ - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item
if ([[item identifier] isEqualToString: @"playlist"] || [[item identifier] isEqualToString: @"medialibrary"])
return YES;
- return [item hasBadge];
+ return ([(VLCSourceListItem*)item badgeValue] != nil);
}
@@ -1009,13 +1009,13 @@ - (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item
return i_playlist_size;
}
- return [item badgeValue];
+ return [[(VLCSourceListItem*)item badgeValue] integerValue];
}
- (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item
{
- return [item hasIcon];
+ return ([item icon] != nil);
}
diff --git a/modules/gui/macosx/VLCPlaylist.h b/modules/gui/macosx/VLCPlaylist.h
index 024af45d08..c5bbb723f8 100644
--- a/modules/gui/macosx/VLCPlaylist.h
+++ b/modules/gui/macosx/VLCPlaylist.h
@@ -23,7 +23,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
-#import "PXSourceList.h"
#import "VLCPLModel.h"
#import "VLCPlaylistView.h"
diff --git a/modules/gui/macosx/VLCPlaylist.m b/modules/gui/macosx/VLCPlaylist.m
index f5c6729761..07413d05a5 100644
--- a/modules/gui/macosx/VLCPlaylist.m
+++ b/modules/gui/macosx/VLCPlaylist.m
@@ -190,8 +190,8 @@ - (void)setPlaylistHeaderView:(NSTableHeaderView * __nullable)playlistHeaderView
BOOL hasTitleItem = NO;
for (NSArray *column in columnArray) {
- NSString *columnName = column[0];
- NSNumber *columnWidth = column[1];
+ NSString *columnName = [column objectAtIndex:0];
+ NSNumber *columnWidth = [column objectAtIndex:1];
if ([columnName isEqualToString:STATUS_COLUMN])
continue;
diff --git a/modules/gui/macosx/VLCSourceListItem.h b/modules/gui/macosx/VLCSourceListItem.h
new file mode 100644
index 0000000000..dace2562aa
--- /dev/null
+++ b/modules/gui/macosx/VLCSourceListItem.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * VLCSourceListItem.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2018 VLC authors and VideoLAN
+ * $Id$
+ *
+ * Authors: Marvin Scholz <epirat07 at gmail dot com>
+ *
+ * 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 "PXSourceList/PXSourceListItem.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCSourceListItem : PXSourceListItem
+
+ at property NSInteger sdtype;
+
+ at end
+
+NS_ASSUME_NONNULL_END
diff --git a/modules/gui/macosx/VLCSourceListItem.m b/modules/gui/macosx/VLCSourceListItem.m
new file mode 100644
index 0000000000..a2e505b239
--- /dev/null
+++ b/modules/gui/macosx/VLCSourceListItem.m
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ * VLCSourceListItem.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2018 VLC authors and VideoLAN
+ * $Id$
+ *
+ * Authors: Marvin Scholz <epirat07 at gmail dot com>
+ *
+ * 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 "VLCSourceListItem.h"
+
+ at implementation VLCSourceListItem
+
+ at end
--
2.24.3 (Apple Git-128)
More information about the vlc-devel
mailing list