Restore the File Tree, now with a chooser button
Revert "Remove the file tree, as Sandbox does not permit"
This reverts commit 35400e1320
.
This also changes how the File Tree choosing works.
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
xcode15
parent
73c4360b1d
commit
099588b7bd
|
@ -2,6 +2,7 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class FileTreeViewController;
|
||||
@class PlaybackController;
|
||||
@class PlaylistController;
|
||||
@class PlaylistView;
|
||||
|
@ -19,6 +20,7 @@
|
|||
|
||||
IBOutlet NSWindow *mainWindow;
|
||||
IBOutlet NSWindow *miniWindow;
|
||||
IBOutlet NSSplitView *mainView;
|
||||
|
||||
IBOutlet NSSegmentedControl *playbackButtons;
|
||||
IBOutlet NSButton *fileButton;
|
||||
|
@ -47,6 +49,8 @@
|
|||
|
||||
IBOutlet SUUpdater *updater;
|
||||
|
||||
IBOutlet FileTreeViewController *fileTreeViewController;
|
||||
|
||||
IBOutlet PreferencesController *preferencesController;
|
||||
|
||||
NSOperationQueue *queue; // Since we are the app delegate, we take care of the op queue
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#import "AppController.h"
|
||||
#import "Cog-Swift.h"
|
||||
#import "FileTreeController.h"
|
||||
#import "FileTreeOutlineView.h"
|
||||
#import "FileTreeViewController.h"
|
||||
#import "FontSizetoLineHeightTransformer.h"
|
||||
#import "OpenURLPanel.h"
|
||||
#import "PathNode.h"
|
||||
#import "PlaybackController.h"
|
||||
#import "PlaylistController.h"
|
||||
#import "PlaylistEntry.h"
|
||||
|
@ -245,11 +249,50 @@ static AppController *kAppController = nil;
|
|||
[self setFloatingMiniWindow:[[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:@"floatingMiniWindow"]];
|
||||
|
||||
// We need file tree view to restore its state here
|
||||
// so attempt to access file tree view controller's root view
|
||||
// to force it to read nib and create file tree view for us
|
||||
//
|
||||
// TODO: there probably is a more elegant way to do all this
|
||||
// but i'm too stupid/tired to figure it out now
|
||||
[fileTreeViewController view];
|
||||
|
||||
FileTreeOutlineView *outlineView = [fileTreeViewController outlineView];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nodeExpanded:) name:NSOutlineViewItemDidExpandNotification object:outlineView];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nodeCollapsed:) name:NSOutlineViewItemDidCollapseNotification object:outlineView];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDockMenu:) name:CogPlaybackDidBeginNotficiation object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDockMenu:) name:CogPlaybackDidStopNotficiation object:nil];
|
||||
|
||||
[self updateDockMenu:nil];
|
||||
|
||||
NSArray *expandedNodesArray = [[NSUserDefaults standardUserDefaults] valueForKey:@"fileTreeViewExpandedNodes"];
|
||||
|
||||
if(expandedNodesArray) {
|
||||
expandedNodes = [[NSMutableSet alloc] initWithArray:expandedNodesArray];
|
||||
} else {
|
||||
expandedNodes = [[NSMutableSet alloc] init];
|
||||
}
|
||||
|
||||
DLog(@"Nodes to expand: %@", [expandedNodes description]);
|
||||
|
||||
DLog(@"Num of rows: %ld", [outlineView numberOfRows]);
|
||||
|
||||
if(!outlineView) {
|
||||
DLog(@"outlineView is NULL!");
|
||||
}
|
||||
|
||||
[outlineView reloadData];
|
||||
|
||||
for(NSInteger i = 0; i < [outlineView numberOfRows]; i++) {
|
||||
PathNode *pn = [outlineView itemAtRow:i];
|
||||
NSString *str = [[pn URL] absoluteString];
|
||||
|
||||
if([expandedNodes containsObject:str]) {
|
||||
[outlineView expandItem:pn];
|
||||
}
|
||||
}
|
||||
|
||||
[self addObserver:self
|
||||
forKeyPath:@"playlistController.currentEntry"
|
||||
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
|
||||
|
@ -337,6 +380,20 @@ static AppController *kAppController = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)nodeExpanded:(NSNotification *)notification {
|
||||
PathNode *node = [[notification userInfo] objectForKey:@"NSObject"];
|
||||
NSString *url = [[node URL] absoluteString];
|
||||
|
||||
[expandedNodes addObject:url];
|
||||
}
|
||||
|
||||
- (void)nodeCollapsed:(NSNotification *)notification {
|
||||
PathNode *node = [[notification userInfo] objectForKey:@"NSObject"];
|
||||
NSString *url = [[node URL] absoluteString];
|
||||
|
||||
[expandedNodes removeObject:url];
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
||||
if(playbackController.progressOverall) {
|
||||
[playbackController.progressOverall addObserver:self forKeyPath:@"finished" options:0 context:kAppControllerContext];
|
||||
|
@ -410,6 +467,7 @@ static AppController *kAppController = nil;
|
|||
|
||||
DLog(@"Saving expanded nodes: %@", [expandedNodes description]);
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setValue:[expandedNodes allObjects] forKey:@"fileTreeViewExpandedNodes"];
|
||||
// Workaround window not restoring it's size and position.
|
||||
[miniWindow setContentSize:NSMakeSize(miniWindow.frame.size.width, 1)];
|
||||
[miniWindow saveFrameUsingName:@"Mini Window"];
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="FileTreeViewController">
|
||||
<connections>
|
||||
<outlet property="fileTreeOutlineView" destination="69" id="141"/>
|
||||
<outlet property="firstResponder" destination="69" id="140"/>
|
||||
<outlet property="view" destination="55" id="103"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="9" userLabel="FileTreeDataSource" customClass="FileTreeDataSource">
|
||||
<connections>
|
||||
<outlet property="outlineView" destination="69" id="88"/>
|
||||
<outlet property="pathControl" destination="65" id="109"/>
|
||||
<outlet property="watcher" destination="31" id="34"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<userDefaultsController representsSharedInstance="YES" id="27"/>
|
||||
<customObject id="31" customClass="PathWatcher">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="9" id="33"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customView id="55" userLabel="File Tree View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<pathControl focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="65">
|
||||
<rect key="frame" x="76" y="374" width="224" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<pathCell key="cell" selectable="YES" enabled="NO" focusRingType="none" alignment="left" pathStyle="popUp" id="66">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="backgroundColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</pathCell>
|
||||
<connections>
|
||||
<binding destination="27" name="value" keyPath="values.fileTreeRootURL" id="108">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">StringToURLTransformer</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</pathControl>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="line" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="147">
|
||||
<rect key="frame" x="0.0" y="373" width="300" height="1"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" id="Dg2-ay-LZH">
|
||||
<rect key="frame" x="1" y="1" width="298" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<color key="borderColor" name="scrollBarColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="fillColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<font key="titleFont" metaFont="system"/>
|
||||
</box>
|
||||
<scrollView fixedFrame="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="23" horizontalPageScroll="10" verticalLineScroll="23" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="64">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="373"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="OYe-Aa-Spw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="373"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" columnReordering="NO" autosaveColumns="NO" autosaveName="FileTree" rowHeight="18" indentationPerLevel="14" autoresizesOutlineColumn="YES" outlineTableColumn="70" id="69" customClass="FileTreeOutlineView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="373"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="5"/>
|
||||
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn editable="NO" width="268" minWidth="16" maxWidth="1000" id="70">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="71" customClass="FileIconCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<binding destination="27" name="fontSize" keyPath="values.fontSize" id="93"/>
|
||||
</connections>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<binding destination="27" name="rowHeight" keyPath="values.fontSize" id="86">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">FontSizetoLineHeightTransformer</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
<outlet property="dataSource" destination="9" id="87"/>
|
||||
<outlet property="delegate" destination="94" id="98"/>
|
||||
<outlet property="menu" destination="110" id="121"/>
|
||||
</connections>
|
||||
</outlineView>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="67">
|
||||
<rect key="frame" x="0.0" y="362" width="306" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="68">
|
||||
<rect key="frame" x="261" y="0.0" width="15" height="363"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<connections>
|
||||
<outlet property="nextKeyView" destination="69" id="104"/>
|
||||
</connections>
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Tqu-Wl-fBM">
|
||||
<rect key="frame" x="-2" y="370" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Choose" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vRe-3U-Nxj">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="chooseRootFolder:" target="-2" id="aZ6-tK-wqz"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-310" y="119"/>
|
||||
</customView>
|
||||
<customObject id="94" customClass="FileTreeController">
|
||||
<connections>
|
||||
<outlet property="controller" destination="-2" id="106"/>
|
||||
<outlet property="dataSource" destination="9" id="137"/>
|
||||
<outlet property="outlineView" destination="69" id="95"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<menu title="Menu" id="110" userLabel="ContextualMenu">
|
||||
<items>
|
||||
<menuItem title="Add to Playlist" tag="1" id="119">
|
||||
<connections>
|
||||
<action selector="addToPlaylist:" target="94" id="122"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Set as Playlist" tag="2" id="129">
|
||||
<connections>
|
||||
<action selector="setAsPlaylist:" target="94" id="130"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="128"/>
|
||||
<menuItem title="Show in Finder" tag="3" id="112">
|
||||
<connections>
|
||||
<action selector="showEntryInFinder:" target="94" id="123"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="126"/>
|
||||
<menuItem title="Set as Root" tag="4" id="124">
|
||||
<connections>
|
||||
<action selector="setAsRoot:" target="94" id="125"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="69" id="139"/>
|
||||
</connections>
|
||||
</menu>
|
||||
</objects>
|
||||
</document>
|
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,7 @@
|
|||
172A12330F5911D20078EF0C /* RepeatTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = 172A12320F5911D20078EF0C /* RepeatTransformers.m */; };
|
||||
172A123C0F5912AE0078EF0C /* ShuffleTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = 172A123B0F5912AE0078EF0C /* ShuffleTransformers.m */; };
|
||||
172A12A90F59AF8A0078EF0C /* NSString+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 172A12A80F59AF8A0078EF0C /* NSString+CogSort.m */; };
|
||||
173855FF0E0CC81F00488CD4 /* FileTreeOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 173855FE0E0CC81F00488CD4 /* FileTreeOutlineView.m */; };
|
||||
1752C36C0F59E00100F85F28 /* PlaybackButtons.m in Sources */ = {isa = PBXBuildFile; fileRef = 1752C36B0F59E00100F85F28 /* PlaybackButtons.m */; };
|
||||
1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */; };
|
||||
1770429C0B8BC53600B86321 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 177042980B8BC53600B86321 /* AppController.m */; };
|
||||
|
@ -40,8 +41,20 @@
|
|||
17818A990C0B27AC001C4916 /* shn.icns in Resources */ = {isa = PBXBuildFile; fileRef = 17818A920C0B27AC001C4916 /* shn.icns */; };
|
||||
17818A9A0C0B27AC001C4916 /* wav.icns in Resources */ = {isa = PBXBuildFile; fileRef = 17818A930C0B27AC001C4916 /* wav.icns */; };
|
||||
17818A9B0C0B27AC001C4916 /* wv.icns in Resources */ = {isa = PBXBuildFile; fileRef = 17818A940C0B27AC001C4916 /* wv.icns */; };
|
||||
1784560F0F631E24007E8021 /* FileTreeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1784560E0F631E24007E8021 /* FileTreeViewController.m */; };
|
||||
178456120F631E31007E8021 /* SideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 178456110F631E31007E8021 /* SideViewController.m */; };
|
||||
1791FF900CB43A2C0070BC5C /* MediaKeysApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1791FF8E0CB43A2C0070BC5C /* MediaKeysApplication.m */; };
|
||||
179790E10C087AB7001D6996 /* OpenURLPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = 179790DF0C087AB7001D6996 /* OpenURLPanel.m */; };
|
||||
179D031E0E0CB2500064A77A /* ContainedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D03090E0CB2500064A77A /* ContainedNode.m */; };
|
||||
179D031F0E0CB2500064A77A /* ContainerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D030B0E0CB2500064A77A /* ContainerNode.m */; };
|
||||
179D03200E0CB2500064A77A /* DirectoryNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D030D0E0CB2500064A77A /* DirectoryNode.m */; };
|
||||
179D03210E0CB2500064A77A /* FileIconCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D030F0E0CB2500064A77A /* FileIconCell.m */; };
|
||||
179D03220E0CB2500064A77A /* FileNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D03110E0CB2500064A77A /* FileNode.m */; };
|
||||
179D03230E0CB2500064A77A /* FileTreeDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D03130E0CB2500064A77A /* FileTreeDataSource.m */; };
|
||||
179D03240E0CB2500064A77A /* FileTreeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D03150E0CB2500064A77A /* FileTreeController.m */; };
|
||||
179D03260E0CB2500064A77A /* PathNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D03190E0CB2500064A77A /* PathNode.m */; };
|
||||
179D03270E0CB2500064A77A /* PathWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D031B0E0CB2500064A77A /* PathWatcher.m */; };
|
||||
179D03280E0CB2500064A77A /* SmartFolderNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 179D031D0E0CB2500064A77A /* SmartFolderNode.m */; };
|
||||
17BB5CED0B8A86010009ACB1 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BB5CEC0B8A86010009ACB1 /* AudioToolbox.framework */; };
|
||||
17BB5CF90B8A86350009ACB1 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BB5CF60B8A86350009ACB1 /* AudioUnit.framework */; };
|
||||
17BB5CFA0B8A86350009ACB1 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BB5CF70B8A86350009ACB1 /* CoreAudio.framework */; };
|
||||
|
@ -185,6 +198,7 @@
|
|||
83BC5ABF20E4CE7A00631CD4 /* InfoInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B0D00F6320EA00694C57 /* InfoInspector.xib */; };
|
||||
83BC5AC020E4CE7D00631CD4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17342A980D5FD20B00E8D854 /* MainMenu.xib */; };
|
||||
83BC5AC120E4CE8700631CD4 /* OpenURLPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17342ABD0D5FD36400E8D854 /* OpenURLPanel.xib */; };
|
||||
83BC5AC220E4CE8A00631CD4 /* FileTree.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17211A7C0D68B7C500911CA9 /* FileTree.xib */; };
|
||||
83BC5AC320E4CE8D00631CD4 /* SpotlightPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 178456C00F6320B5007E8021 /* SpotlightPanel.xib */; };
|
||||
83BC5AC420E4CE9000631CD4 /* Feedback.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B1DA0F6330D400694C57 /* Feedback.xib */; };
|
||||
83BCB8DE17FC971300760340 /* FFMPEG.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = B09E94350D747F7B0064F138 /* FFMPEG.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
|
@ -775,6 +789,8 @@
|
|||
172A123B0F5912AE0078EF0C /* ShuffleTransformers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShuffleTransformers.m; path = Window/ShuffleTransformers.m; sourceTree = "<group>"; };
|
||||
172A12A70F59AF8A0078EF0C /* NSString+CogSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+CogSort.h"; sourceTree = "<group>"; };
|
||||
172A12A80F59AF8A0078EF0C /* NSString+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+CogSort.m"; sourceTree = "<group>"; };
|
||||
173855FD0E0CC81F00488CD4 /* FileTreeOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileTreeOutlineView.h; path = FileTree/FileTreeOutlineView.h; sourceTree = "<group>"; };
|
||||
173855FE0E0CC81F00488CD4 /* FileTreeOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileTreeOutlineView.m; path = FileTree/FileTreeOutlineView.m; sourceTree = "<group>"; };
|
||||
1752C36A0F59E00100F85F28 /* PlaybackButtons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaybackButtons.h; path = Window/PlaybackButtons.h; sourceTree = "<group>"; };
|
||||
1752C36B0F59E00100F85F28 /* PlaybackButtons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PlaybackButtons.m; path = Window/PlaybackButtons.m; sourceTree = "<group>"; };
|
||||
1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PlaylistLoader.h; sourceTree = "<group>"; };
|
||||
|
@ -800,10 +816,34 @@
|
|||
17818A920C0B27AC001C4916 /* shn.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = shn.icns; sourceTree = "<group>"; };
|
||||
17818A930C0B27AC001C4916 /* wav.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = wav.icns; sourceTree = "<group>"; };
|
||||
17818A940C0B27AC001C4916 /* wv.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = wv.icns; sourceTree = "<group>"; };
|
||||
1784560D0F631E24007E8021 /* FileTreeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileTreeViewController.h; path = FileTree/FileTreeViewController.h; sourceTree = "<group>"; };
|
||||
1784560E0F631E24007E8021 /* FileTreeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileTreeViewController.m; path = FileTree/FileTreeViewController.m; sourceTree = "<group>"; };
|
||||
178456100F631E31007E8021 /* SideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SideViewController.h; sourceTree = "<group>"; };
|
||||
178456110F631E31007E8021 /* SideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SideViewController.m; sourceTree = "<group>"; };
|
||||
1791FF8D0CB43A2C0070BC5C /* MediaKeysApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaKeysApplication.h; sourceTree = "<group>"; };
|
||||
1791FF8E0CB43A2C0070BC5C /* MediaKeysApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaKeysApplication.m; sourceTree = "<group>"; };
|
||||
179790DE0C087AB7001D6996 /* OpenURLPanel.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = OpenURLPanel.h; sourceTree = "<group>"; };
|
||||
179790DF0C087AB7001D6996 /* OpenURLPanel.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = OpenURLPanel.m; sourceTree = "<group>"; };
|
||||
179D03080E0CB2500064A77A /* ContainedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContainedNode.h; path = FileTree/ContainedNode.h; sourceTree = "<group>"; };
|
||||
179D03090E0CB2500064A77A /* ContainedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContainedNode.m; path = FileTree/ContainedNode.m; sourceTree = "<group>"; };
|
||||
179D030A0E0CB2500064A77A /* ContainerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContainerNode.h; path = FileTree/ContainerNode.h; sourceTree = "<group>"; };
|
||||
179D030B0E0CB2500064A77A /* ContainerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContainerNode.m; path = FileTree/ContainerNode.m; sourceTree = "<group>"; };
|
||||
179D030C0E0CB2500064A77A /* DirectoryNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryNode.h; path = FileTree/DirectoryNode.h; sourceTree = "<group>"; };
|
||||
179D030D0E0CB2500064A77A /* DirectoryNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DirectoryNode.m; path = FileTree/DirectoryNode.m; sourceTree = "<group>"; };
|
||||
179D030E0E0CB2500064A77A /* FileIconCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileIconCell.h; path = FileTree/FileIconCell.h; sourceTree = "<group>"; };
|
||||
179D030F0E0CB2500064A77A /* FileIconCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileIconCell.m; path = FileTree/FileIconCell.m; sourceTree = "<group>"; };
|
||||
179D03100E0CB2500064A77A /* FileNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileNode.h; path = FileTree/FileNode.h; sourceTree = "<group>"; };
|
||||
179D03110E0CB2500064A77A /* FileNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileNode.m; path = FileTree/FileNode.m; sourceTree = "<group>"; };
|
||||
179D03120E0CB2500064A77A /* FileTreeDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileTreeDataSource.h; path = FileTree/FileTreeDataSource.h; sourceTree = "<group>"; };
|
||||
179D03130E0CB2500064A77A /* FileTreeDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileTreeDataSource.m; path = FileTree/FileTreeDataSource.m; sourceTree = "<group>"; };
|
||||
179D03140E0CB2500064A77A /* FileTreeController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileTreeController.h; path = FileTree/FileTreeController.h; sourceTree = "<group>"; };
|
||||
179D03150E0CB2500064A77A /* FileTreeController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileTreeController.m; path = FileTree/FileTreeController.m; sourceTree = "<group>"; };
|
||||
179D03180E0CB2500064A77A /* PathNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathNode.h; path = FileTree/PathNode.h; sourceTree = "<group>"; };
|
||||
179D03190E0CB2500064A77A /* PathNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PathNode.m; path = FileTree/PathNode.m; sourceTree = "<group>"; };
|
||||
179D031A0E0CB2500064A77A /* PathWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathWatcher.h; path = FileTree/PathWatcher.h; sourceTree = "<group>"; };
|
||||
179D031B0E0CB2500064A77A /* PathWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PathWatcher.m; path = FileTree/PathWatcher.m; sourceTree = "<group>"; };
|
||||
179D031C0E0CB2500064A77A /* SmartFolderNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmartFolderNode.h; path = FileTree/SmartFolderNode.h; sourceTree = "<group>"; };
|
||||
179D031D0E0CB2500064A77A /* SmartFolderNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SmartFolderNode.m; path = FileTree/SmartFolderNode.m; sourceTree = "<group>"; };
|
||||
17BB5CEC0B8A86010009ACB1 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<absolute>"; };
|
||||
17BB5CF60B8A86350009ACB1 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = "<absolute>"; };
|
||||
17BB5CF70B8A86350009ACB1 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
|
||||
|
@ -1012,6 +1052,7 @@
|
|||
83BC5AB420E4C91100631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/InfoInspector.xib; sourceTree = "<group>"; };
|
||||
83BC5AB520E4C91200631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
83BC5AB620E4C91300631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/OpenURLPanel.xib; sourceTree = "<group>"; };
|
||||
83BC5AB720E4C91400631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/FileTree.xib; sourceTree = "<group>"; };
|
||||
83BC5AB820E4C91400631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SpotlightPanel.xib; sourceTree = "<group>"; };
|
||||
83BC5AB920E4C91500631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Feedback.xib; sourceTree = "<group>"; };
|
||||
83BC5AC620E4D04600631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
||||
|
@ -1020,6 +1061,8 @@
|
|||
83BC5ACC20E4D07700631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoInspector.strings; sourceTree = "<group>"; };
|
||||
83BC5ACE20E4D09700631CD4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/OpenURLPanel.strings; sourceTree = "<group>"; };
|
||||
83BC5AD020E4D09800631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/OpenURLPanel.strings; sourceTree = "<group>"; };
|
||||
83BC5AD220E4D0B400631CD4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/FileTree.strings; sourceTree = "<group>"; };
|
||||
83BC5AD420E4D0B600631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/FileTree.strings; sourceTree = "<group>"; };
|
||||
83BC5AD620E4D0D800631CD4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/SpotlightPanel.strings; sourceTree = "<group>"; };
|
||||
83BC5AD820E4D0D900631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SpotlightPanel.strings; sourceTree = "<group>"; };
|
||||
83BC5ADA20E4D0E900631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Feedback.strings; sourceTree = "<group>"; };
|
||||
|
@ -1102,6 +1145,7 @@
|
|||
8377C66027B8CF2300E8BC0F /* Visualization */,
|
||||
8E75752A09F31D5A0080F1EE /* Playlist */,
|
||||
8E07AAEA0AAC90DC00A4B32F /* Preferences */,
|
||||
17DDF6400E0CB6F100A2E4AD /* FileTree */,
|
||||
830C37A227B95E6000E02BB0 /* Equalizer */,
|
||||
17D1B0FE0F63252900694C57 /* InfoInspector */,
|
||||
569C52C50D5F2BD500BDBDC9 /* Spotlight */,
|
||||
|
@ -1214,6 +1258,8 @@
|
|||
83988F0D27BE0A5900A0E89A /* RedundantPlaylistDataStore.m */,
|
||||
8381A09027C5F72F00A1C530 /* SHA256Digest.h */,
|
||||
8381A09127C5F72F00A1C530 /* SHA256Digest.m */,
|
||||
178456100F631E31007E8021 /* SideViewController.h */,
|
||||
178456110F631E31007E8021 /* SideViewController.m */,
|
||||
8370D739277419D200245CE0 /* SQLiteStore.h */,
|
||||
8370D73C277419F700245CE0 /* SQLiteStore.m */,
|
||||
17FAEBAA0F662985007C8707 /* ToolTipTextField.h */,
|
||||
|
@ -1363,6 +1409,37 @@
|
|||
name = InfoInspector;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17DDF6400E0CB6F100A2E4AD /* FileTree */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1784560D0F631E24007E8021 /* FileTreeViewController.h */,
|
||||
1784560E0F631E24007E8021 /* FileTreeViewController.m */,
|
||||
179D03140E0CB2500064A77A /* FileTreeController.h */,
|
||||
179D03150E0CB2500064A77A /* FileTreeController.m */,
|
||||
173855FD0E0CC81F00488CD4 /* FileTreeOutlineView.h */,
|
||||
173855FE0E0CC81F00488CD4 /* FileTreeOutlineView.m */,
|
||||
179D03120E0CB2500064A77A /* FileTreeDataSource.h */,
|
||||
179D03130E0CB2500064A77A /* FileTreeDataSource.m */,
|
||||
179D03080E0CB2500064A77A /* ContainedNode.h */,
|
||||
179D03090E0CB2500064A77A /* ContainedNode.m */,
|
||||
179D030A0E0CB2500064A77A /* ContainerNode.h */,
|
||||
179D030B0E0CB2500064A77A /* ContainerNode.m */,
|
||||
179D030C0E0CB2500064A77A /* DirectoryNode.h */,
|
||||
179D030D0E0CB2500064A77A /* DirectoryNode.m */,
|
||||
179D030E0E0CB2500064A77A /* FileIconCell.h */,
|
||||
179D030F0E0CB2500064A77A /* FileIconCell.m */,
|
||||
179D03100E0CB2500064A77A /* FileNode.h */,
|
||||
179D03110E0CB2500064A77A /* FileNode.m */,
|
||||
179D03180E0CB2500064A77A /* PathNode.h */,
|
||||
179D03190E0CB2500064A77A /* PathNode.m */,
|
||||
179D031A0E0CB2500064A77A /* PathWatcher.h */,
|
||||
179D031B0E0CB2500064A77A /* PathWatcher.m */,
|
||||
179D031C0E0CB2500064A77A /* SmartFolderNode.h */,
|
||||
179D031D0E0CB2500064A77A /* SmartFolderNode.m */,
|
||||
);
|
||||
name = FileTree;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17E0D5D20F520E75005B6FED /* Window */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1489,6 +1566,7 @@
|
|||
17D1B0D00F6320EA00694C57 /* InfoInspector.xib */,
|
||||
17342A980D5FD20B00E8D854 /* MainMenu.xib */,
|
||||
17342ABD0D5FD36400E8D854 /* OpenURLPanel.xib */,
|
||||
17211A7C0D68B7C500911CA9 /* FileTree.xib */,
|
||||
178456C00F6320B5007E8021 /* SpotlightPanel.xib */,
|
||||
17E41E060C130DFF00AC744D /* Credits.html */,
|
||||
17D1B1DA0F6330D400694C57 /* Feedback.xib */,
|
||||
|
@ -2414,6 +2492,7 @@
|
|||
836F462C28207FA4005B9B87 /* PauseNormal.png in Resources */,
|
||||
83BC5AC420E4CE9000631CD4 /* Feedback.xib in Resources */,
|
||||
83BC5AC320E4CE8D00631CD4 /* SpotlightPanel.xib in Resources */,
|
||||
83BC5AC220E4CE8A00631CD4 /* FileTree.xib in Resources */,
|
||||
83BC5AC120E4CE8700631CD4 /* OpenURLPanel.xib in Resources */,
|
||||
83BC5AC020E4CE7D00631CD4 /* MainMenu.xib in Resources */,
|
||||
83BC5ABF20E4CE7A00631CD4 /* InfoInspector.xib in Resources */,
|
||||
|
@ -2568,12 +2647,23 @@
|
|||
170B55940D6E5E7B006B9E92 /* StatusImageTransformer.m in Sources */,
|
||||
830C37FC27B9956C00E02BB0 /* analyzer.c in Sources */,
|
||||
17249F0F0D82E17700F33392 /* ToggleQueueTitleTransformer.m in Sources */,
|
||||
179D031E0E0CB2500064A77A /* ContainedNode.m in Sources */,
|
||||
179D031F0E0CB2500064A77A /* ContainerNode.m in Sources */,
|
||||
834B05EA2859C006000B7DC0 /* TotalTimeTransformer.m in Sources */,
|
||||
839DA7CF274A2D4C001B18E5 /* NSDictionary+Merge.m in Sources */,
|
||||
179D03200E0CB2500064A77A /* DirectoryNode.m in Sources */,
|
||||
179D03210E0CB2500064A77A /* FileIconCell.m in Sources */,
|
||||
179D03220E0CB2500064A77A /* FileNode.m in Sources */,
|
||||
0A9CEA0B286152DF00E47168 /* DraggableView.swift in Sources */,
|
||||
83988F0E27BE0A5900A0E89A /* RedundantPlaylistDataStore.m in Sources */,
|
||||
179D03230E0CB2500064A77A /* FileTreeDataSource.m in Sources */,
|
||||
179D03240E0CB2500064A77A /* FileTreeController.m in Sources */,
|
||||
8370D73D277419F700245CE0 /* SQLiteStore.m in Sources */,
|
||||
179D03260E0CB2500064A77A /* PathNode.m in Sources */,
|
||||
179D03270E0CB2500064A77A /* PathWatcher.m in Sources */,
|
||||
179D03280E0CB2500064A77A /* SmartFolderNode.m in Sources */,
|
||||
8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */,
|
||||
173855FF0E0CC81F00488CD4 /* FileTreeOutlineView.m in Sources */,
|
||||
07D971E60ED1DAA800E7602E /* TagEditorController.m in Sources */,
|
||||
17E0D5EA0F520F02005B6FED /* MainWindow.m in Sources */,
|
||||
836D28A818086386005B7299 /* MiniModeMenuTitleTransformer.m in Sources */,
|
||||
|
@ -2596,6 +2686,8 @@
|
|||
8307D30E28606148000FF8EB /* SandboxBroker.m in Sources */,
|
||||
83229C9F283B0095004626A8 /* SpectrumWindowController.m in Sources */,
|
||||
835F00BB279BD1CD00055FCF /* SecondsFormatter.m in Sources */,
|
||||
1784560F0F631E24007E8021 /* FileTreeViewController.m in Sources */,
|
||||
178456120F631E31007E8021 /* SideViewController.m in Sources */,
|
||||
17D1B1010F63255200694C57 /* InfoWindowController.m in Sources */,
|
||||
835A8FD327957310005B3C39 /* json.c in Sources */,
|
||||
17D1B25D0F633A4F00694C57 /* PreferencePluginController.m in Sources */,
|
||||
|
@ -2778,6 +2870,16 @@
|
|||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17211A7C0D68B7C500911CA9 /* FileTree.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
83BC5AB720E4C91400631CD4 /* Base */,
|
||||
83BC5AD220E4D0B400631CD4 /* es */,
|
||||
83BC5AD420E4D0B600631CD4 /* en */,
|
||||
);
|
||||
name = FileTree.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17342A980D5FD20B00E8D854 /* MainMenu.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// ContainedNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 10/15/07.
|
||||
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "PathNode.h"
|
||||
|
||||
@interface ContainedNode : PathNode {
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// ContainedNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 10/15/07.
|
||||
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ContainedNode.h"
|
||||
#import "CogAudio/AudioMetadataReader.h"
|
||||
|
||||
@implementation ContainedNode
|
||||
|
||||
- (BOOL)isLeaf {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)u {
|
||||
[super setURL:u];
|
||||
|
||||
if([u fragment]) {
|
||||
NSDictionary *metadata = [AudioMetadataReader metadataForURL:u];
|
||||
NSString *title = nil;
|
||||
NSString *artist = nil;
|
||||
if(metadata) {
|
||||
title = [metadata valueForKey:@"title"];
|
||||
artist = [metadata valueForKey:@"artist"];
|
||||
}
|
||||
|
||||
if(title && [title length]) {
|
||||
if(artist && [artist length]) {
|
||||
display = [[u fragment] stringByAppendingFormat:@": %@ - %@", artist, title];
|
||||
} else {
|
||||
display = [[u fragment] stringByAppendingFormat:@": %@", title];
|
||||
}
|
||||
} else {
|
||||
display = [u fragment];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// ContainerNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 10/15/07.
|
||||
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "PathNode.h"
|
||||
|
||||
@interface ContainerNode : PathNode {
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// ContainerNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 10/15/07.
|
||||
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ContainerNode.h"
|
||||
#import "CogAudio/AudioContainer.h"
|
||||
|
||||
#import "ContainedNode.h"
|
||||
|
||||
#import "Logging.h"
|
||||
|
||||
@implementation ContainerNode
|
||||
|
||||
- (BOOL)isLeaf {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)updatePath {
|
||||
NSArray *urls = [AudioContainer urlsForContainerURL:url];
|
||||
|
||||
NSMutableArray *paths = [[NSMutableArray alloc] init];
|
||||
for(NSURL *u in urls) {
|
||||
ContainedNode *node = [[ContainedNode alloc] initWithDataSource:dataSource url:u];
|
||||
DLog(@"Node: %@", u);
|
||||
[paths addObject:node];
|
||||
}
|
||||
|
||||
[self setSubpaths:paths];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// DirectoryNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/2006.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PathNode.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface DirectoryNode : PathNode {
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// DirectoryNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/2006.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DirectoryNode.h"
|
||||
|
||||
#import "FileNode.h"
|
||||
#import "SmartFolderNode.h"
|
||||
|
||||
#import "NSString+FinderCompare.h"
|
||||
|
||||
@implementation DirectoryNode
|
||||
|
||||
- (BOOL)isLeaf {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)updatePath {
|
||||
if(!url) return;
|
||||
|
||||
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:url
|
||||
includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey]
|
||||
options:(NSDirectoryEnumerationSkipsSubdirectoryDescendants | NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsHiddenFiles)
|
||||
errorHandler:^BOOL(NSURL *url, NSError *error) {
|
||||
return NO;
|
||||
}];
|
||||
NSMutableArray *fullPaths = [[NSMutableArray alloc] init];
|
||||
|
||||
for(NSURL *theUrl in enumerator) {
|
||||
[fullPaths addObject:[theUrl path]];
|
||||
}
|
||||
|
||||
[self processPaths:[fullPaths sortedArrayUsingSelector:@selector(finderCompare:)]];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// FileIconTextCell.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/06.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ImageTextCell.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface FileIconCell : ImageTextCell {
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// FileIconTextCell.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/06.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileIconCell.h"
|
||||
#import "PathNode.h"
|
||||
|
||||
@implementation FileIconCell
|
||||
|
||||
- (void)setObjectValue:(PathNode *)o {
|
||||
if([o respondsToSelector:@selector(icon)] && [o respondsToSelector:@selector(display)]) {
|
||||
[super setObjectValue:[o display]];
|
||||
[super setImage:[o icon]];
|
||||
} else {
|
||||
[super setObjectValue:(id)o];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// FileNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/2006.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PathNode.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface FileNode : PathNode {
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// FileNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/2006.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileNode.h"
|
||||
|
||||
@implementation FileNode
|
||||
|
||||
- (BOOL)isLeaf {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// FileTreeController.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/17/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileTreeDataSource.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class SideViewController;
|
||||
@interface FileTreeController : NSObject {
|
||||
IBOutlet SideViewController *controller;
|
||||
IBOutlet NSOutlineView *outlineView;
|
||||
IBOutlet FileTreeDataSource *dataSource;
|
||||
}
|
||||
|
||||
- (IBAction)addToPlaylist:(id)sender;
|
||||
- (IBAction)addToPlaylistExternal:(id)sender;
|
||||
- (IBAction)setAsPlaylist:(id)sender;
|
||||
- (IBAction)playPauseResume:(NSObject *)id;
|
||||
- (IBAction)showEntryInFinder:(id)sender;
|
||||
- (IBAction)setAsRoot:(id)sender;
|
||||
|
||||
@end
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// FileTreeController.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/17/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileTreeController.h"
|
||||
#import "PlaylistController.h"
|
||||
#import "SideViewController.h"
|
||||
|
||||
@implementation FileTreeController
|
||||
|
||||
- (IBAction)addToPlaylist:(id)sender {
|
||||
[self doAddToPlaylist:sender origin:URLOriginInternal];
|
||||
}
|
||||
|
||||
- (void)doAddToPlaylist:(id)sender origin:(URLOrigin)origin {
|
||||
NSUInteger index;
|
||||
NSIndexSet *selectedIndexes = [outlineView selectedRowIndexes];
|
||||
NSMutableArray *urls = [[NSMutableArray alloc] init];
|
||||
|
||||
for(index = [selectedIndexes firstIndex];
|
||||
index != NSNotFound; index = [selectedIndexes indexGreaterThanIndex:index]) {
|
||||
[urls addObject:[[outlineView itemAtRow:index] URL]];
|
||||
}
|
||||
|
||||
[controller doAddToPlaylist:urls origin:origin];
|
||||
}
|
||||
|
||||
- (void)addToPlaylistExternal:(id)sender {
|
||||
[self doAddToPlaylist:sender origin:URLOriginExternal];
|
||||
}
|
||||
|
||||
- (IBAction)setAsPlaylist:(id)sender {
|
||||
[controller clear:sender];
|
||||
[self addToPlaylist:sender];
|
||||
}
|
||||
|
||||
- (IBAction)playPauseResume:(NSObject *)id {
|
||||
[controller playPauseResume:id];
|
||||
}
|
||||
|
||||
- (IBAction)showEntryInFinder:(id)sender {
|
||||
NSUInteger index;
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSIndexSet *selectedIndexes = [outlineView selectedRowIndexes];
|
||||
|
||||
for(index = [selectedIndexes firstIndex];
|
||||
index != NSNotFound; index = [selectedIndexes indexGreaterThanIndex:index]) {
|
||||
NSURL *url = [[outlineView itemAtRow:index] URL];
|
||||
[ws selectFile:[url path] inFileViewerRootedAtPath:[url path]];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)setAsRoot:(id)sender {
|
||||
NSUInteger index = [[outlineView selectedRowIndexes] firstIndex];
|
||||
|
||||
if(index != NSNotFound) {
|
||||
[dataSource changeURL:[[outlineView itemAtRow:index] URL]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
|
||||
SEL action = [menuItem action];
|
||||
|
||||
if([outlineView numberOfSelectedRows] == 0)
|
||||
return NO;
|
||||
|
||||
if(action == @selector(setAsRoot:)) {
|
||||
BOOL isDir;
|
||||
NSInteger row = [outlineView selectedRow];
|
||||
|
||||
if([outlineView numberOfSelectedRows] > 1)
|
||||
return NO;
|
||||
|
||||
// Only let directories be Set as Root
|
||||
[[NSFileManager defaultManager] fileExistsAtPath:[[[outlineView itemAtRow:row] URL] path] isDirectory:&isDir];
|
||||
return isDir;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// FileTreeDataSource.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 10/14/07.
|
||||
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class PathNode;
|
||||
@class PathWatcher;
|
||||
|
||||
@interface FileTreeDataSource : NSObject <NSOutlineViewDataSource>
|
||||
|
||||
@property(nonatomic, weak) IBOutlet NSOutlineView *outlineView;
|
||||
@property(nonatomic, weak) IBOutlet NSPathControl *pathControl;
|
||||
@property(nonatomic, weak) IBOutlet PathWatcher *watcher;
|
||||
|
||||
- (void)changeURL:(NSURL *)rootURL;
|
||||
|
||||
- (void)reloadPathNode:(PathNode *)item;
|
||||
|
||||
@end
|
|
@ -0,0 +1,201 @@
|
|||
//
|
||||
// FileTreeDataSource.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 10/14/07.
|
||||
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileTreeDataSource.h"
|
||||
|
||||
#import "DirectoryNode.h"
|
||||
#import "PathWatcher.h"
|
||||
|
||||
#import "Logging.h"
|
||||
|
||||
#import "AppController.h"
|
||||
|
||||
#import "SandboxBroker.h"
|
||||
|
||||
static void *kFileTreeDataSourceContext = &kFileTreeDataSourceContext;
|
||||
|
||||
// XXX this is only for reference, we have the entitlement for the path anyway
|
||||
static NSURL *pathEscape(NSString *path) {
|
||||
NSString *componentsToRemove = [NSString stringWithFormat:@"Library/Containers/%@/Data/", [[NSBundle mainBundle] bundleIdentifier]];
|
||||
NSRange rangeOfMatch = [path rangeOfString:componentsToRemove];
|
||||
if(rangeOfMatch.location != NSNotFound)
|
||||
path = [path stringByReplacingCharactersInRange:rangeOfMatch withString:@""];
|
||||
return [NSURL fileURLWithPath:path];
|
||||
}
|
||||
|
||||
static NSURL *defaultMusicDirectory(void) {
|
||||
NSString *path = [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) lastObject];
|
||||
return pathEscape(path);
|
||||
}
|
||||
|
||||
@interface FileTreeDataSource ()
|
||||
|
||||
@property NSURL *rootURL;
|
||||
|
||||
@property const void *sbHandle;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FileTreeDataSource {
|
||||
PathNode *rootNode;
|
||||
const void *_sbHandle;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
NSString *path = [defaultMusicDirectory() absoluteString];
|
||||
NSDictionary *userDefaultsValuesDict = @{ @"fileTreeRootURL": path };
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
_sbHandle = NULL;
|
||||
[self.pathControl setTarget:self];
|
||||
[self.pathControl setAction:@selector(pathControlAction:)];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
|
||||
forKeyPath:@"values.fileTreeRootURL"
|
||||
options:NSKeyValueObservingOptionNew |
|
||||
NSKeyValueObservingOptionInitial
|
||||
context:kFileTreeDataSourceContext];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context {
|
||||
if(context == kFileTreeDataSourceContext) {
|
||||
if([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
|
||||
NSString *url =
|
||||
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"];
|
||||
DLog(@"File tree root URL: %@\n", url);
|
||||
self.rootURL = [NSURL URLWithString:url];
|
||||
}
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)changeURL:(NSURL *)url {
|
||||
if(url != nil) {
|
||||
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString]
|
||||
forKey:@"fileTreeRootURL"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pathControlAction:(id)sender {
|
||||
NSPathControlItem *item = [self.pathControl clickedPathItem];
|
||||
if(item != nil && item.URL != nil) {
|
||||
[self changeURL:item.URL];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSURL *)rootURL {
|
||||
return [rootNode URL];
|
||||
}
|
||||
|
||||
- (void)setRootURL:(NSURL *)rootURL {
|
||||
SandboxBroker *sharedSandboxBroker = [SandboxBroker sharedSandboxBroker];
|
||||
if(self.sbHandle) [sharedSandboxBroker endFolderAccess:self.sbHandle];
|
||||
self.sbHandle = [sharedSandboxBroker beginFolderAccess:rootURL];
|
||||
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]]) {
|
||||
rootURL = defaultMusicDirectory();
|
||||
}
|
||||
|
||||
rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL];
|
||||
|
||||
[self.watcher setPath:[rootURL path]];
|
||||
|
||||
[self reloadPathNode:rootNode];
|
||||
}
|
||||
|
||||
- (const void *)sbHandle {
|
||||
return _sbHandle;
|
||||
}
|
||||
|
||||
- (void)setSbHandle:(const void *)sbHandle {
|
||||
_sbHandle = sbHandle;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if(self.sbHandle) [[SandboxBroker sharedSandboxBroker] endFolderAccess:self.sbHandle];
|
||||
}
|
||||
|
||||
- (PathNode *)nodeForPath:(NSString *)path {
|
||||
NSString *relativePath = [[path stringByReplacingOccurrencesOfString:[[[self rootURL] path] stringByAppendingString:@"/"]
|
||||
withString:@""
|
||||
options:NSAnchoredSearch
|
||||
range:NSMakeRange(0, [path length])] stringByStandardizingPath];
|
||||
PathNode *node = rootNode;
|
||||
DLog(@"Root | Relative | Path: %@ | %@ | %@", [[self rootURL] path], relativePath, path);
|
||||
for(NSString *c in [relativePath pathComponents]) {
|
||||
DLog(@"COMPONENT: %@", c);
|
||||
BOOL found = NO;
|
||||
for(PathNode *subnode in [node subpaths]) {
|
||||
if([[[[subnode URL] path] lastPathComponent] isEqualToString:c]) {
|
||||
node = subnode;
|
||||
found = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
DLog(@"Not found!");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
- (void)pathDidChange:(NSString *)path {
|
||||
DLog(@"PATH DID CHANGE: %@", path);
|
||||
// Need to find the corresponding node...and call [node reloadPath], then [self reloadPathNode:node]
|
||||
PathNode *node = [self nodeForPath:path];
|
||||
DLog(@"NODE IS: %@", node);
|
||||
[node updatePath];
|
||||
[self reloadPathNode:node];
|
||||
}
|
||||
|
||||
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
|
||||
PathNode *n = (item == nil ? rootNode : item);
|
||||
|
||||
return (int)[[n subpaths] count];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
|
||||
PathNode *n = (item == nil ? rootNode : item);
|
||||
|
||||
return ![n isLeaf];
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
|
||||
PathNode *n = (item == nil ? rootNode : item);
|
||||
|
||||
return [n subpaths][(NSUInteger)index];
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
||||
PathNode *n = (item == nil ? rootNode : item);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
- (id<NSPasteboardWriting>)outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item {
|
||||
NSPasteboardItem *paste = [[NSPasteboardItem alloc] init];
|
||||
[paste setData:[[item URL] dataRepresentation] forType:NSPasteboardTypeFileURL];
|
||||
return paste;
|
||||
}
|
||||
|
||||
- (void)reloadPathNode:(PathNode *)item {
|
||||
if(item == rootNode) {
|
||||
[self.outlineView reloadData];
|
||||
} else {
|
||||
[self.outlineView reloadItem:item reloadChildren:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// FileTreeOutlineView.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 6/21/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface FileTreeOutlineView : NSOutlineView {
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)e;
|
||||
|
||||
@end
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// FileTreeOutlineView.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 6/21/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileTreeOutlineView.h"
|
||||
#import "FileTreeController.h"
|
||||
#import "FileTreeViewController.h"
|
||||
#import "PlaybackController.h"
|
||||
|
||||
@implementation FileTreeOutlineView
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[self setDoubleAction:@selector(addToPlaylistExternal:)];
|
||||
[self setTarget:[self delegate]];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)e {
|
||||
unsigned int modifiers = [e modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagShift | NSEventModifierFlagControl | NSEventModifierFlagOption);
|
||||
NSString *characters = [e characters];
|
||||
unichar c;
|
||||
|
||||
if([characters length] == 1) {
|
||||
c = [characters characterAtIndex:0];
|
||||
|
||||
if(modifiers == 0 && (c == NSEnterCharacter || c == NSCarriageReturnCharacter)) {
|
||||
[(FileTreeController *)[self delegate] addToPlaylistExternal:self];
|
||||
|
||||
return;
|
||||
} else if(modifiers == 0 && c == ' ') {
|
||||
[(FileTreeController *)[self delegate] playPauseResume:self];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[super keyDown:e];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// enables right-click selection for "Show in Finder" contextual menu
|
||||
- (NSMenu *)menuForEvent:(NSEvent *)event {
|
||||
// Find which row is under the cursor
|
||||
[[self window] makeFirstResponder:self];
|
||||
NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
|
||||
NSInteger iRow = [self rowAtPoint:menuPoint];
|
||||
NSMenu *contextMenu = [self menu];
|
||||
|
||||
/* Update the file tree selection before showing menu
|
||||
Preserves the selection if the row under the mouse is selected (to allow for
|
||||
multiple items to be selected), otherwise selects the row under the mouse */
|
||||
BOOL currentRowIsSelected = [[self selectedRowIndexes] containsIndex:iRow];
|
||||
|
||||
if(iRow == -1) {
|
||||
[self deselectAll:self];
|
||||
} else if(!currentRowIsSelected) {
|
||||
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:iRow] byExtendingSelection:NO];
|
||||
}
|
||||
|
||||
return contextMenu;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// SideBarController.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 6/21/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SideViewController.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class PlaylistLoader;
|
||||
@class PlaybackController;
|
||||
@class FileTreeOutlineView;
|
||||
@interface FileTreeViewController : SideViewController {
|
||||
IBOutlet PlaylistLoader *playlistLoader;
|
||||
IBOutlet PlaybackController *playbackController;
|
||||
IBOutlet FileTreeOutlineView *fileTreeOutlineView;
|
||||
}
|
||||
|
||||
- (FileTreeOutlineView *)outlineView;
|
||||
|
||||
- (IBAction)chooseRootFolder:(id)sender;
|
||||
|
||||
@end
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// SplitViewController.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 6/20/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FileTreeViewController.h"
|
||||
#import "PlaybackController.h"
|
||||
#import "PlaylistLoader.h"
|
||||
#import "SandboxBroker.h"
|
||||
|
||||
@implementation FileTreeViewController
|
||||
|
||||
- (id)init {
|
||||
return [super initWithNibName:@"FileTree" bundle:[NSBundle mainBundle]];
|
||||
}
|
||||
|
||||
- (void)addToPlaylistInternal:(NSArray *)urls {
|
||||
[self doAddToPlaylist:urls origin:URLOriginInternal];
|
||||
}
|
||||
|
||||
- (void)addToPlaylistExternal:(NSArray *)urls {
|
||||
[self doAddToPlaylist:urls origin:URLOriginExternal];
|
||||
}
|
||||
|
||||
- (void)doAddToPlaylist:(NSArray *)urls origin:(URLOrigin)origin {
|
||||
[playlistLoader willInsertURLs:urls origin:origin];
|
||||
[playlistLoader didInsertURLs:[playlistLoader addURLs:urls sort:YES] origin:origin];
|
||||
}
|
||||
|
||||
- (void)clear:(id)sender {
|
||||
[playlistLoader clear:sender];
|
||||
}
|
||||
|
||||
- (void)playPauseResume:(NSObject *)id {
|
||||
[playbackController playPauseResume:id];
|
||||
}
|
||||
|
||||
- (FileTreeOutlineView *)outlineView {
|
||||
return fileTreeOutlineView;
|
||||
}
|
||||
|
||||
- (IBAction)chooseRootFolder:(id)sender {
|
||||
NSString *path = [[NSUserDefaults standardUserDefaults] stringForKey:@"fileTreeRootURL"];
|
||||
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setAllowsMultipleSelection:NO];
|
||||
[panel setCanChooseDirectories:YES];
|
||||
[panel setCanChooseFiles:NO];
|
||||
[panel setFloatingPanel:YES];
|
||||
if(path) {
|
||||
[panel setDirectoryURL:[NSURL fileURLWithPath:path]];
|
||||
}
|
||||
[panel setTitle:@"Open to choose tree path"];
|
||||
NSInteger result = [panel runModal];
|
||||
if(result == NSModalResponseOK) {
|
||||
[[SandboxBroker sharedSandboxBroker] addFolderIfMissing:[panel URL]];
|
||||
[[NSUserDefaults standardUserDefaults] setValue:[[panel URL] absoluteString] forKey:@"fileTreeRootURL"];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Node.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/2006.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class FileTreeDataSource;
|
||||
|
||||
@interface PathNode : NSObject {
|
||||
FileTreeDataSource *dataSource;
|
||||
|
||||
NSURL *url;
|
||||
NSString *display; // The pretty path to display.
|
||||
|
||||
NSImage *icon;
|
||||
|
||||
NSArray *subpaths;
|
||||
}
|
||||
|
||||
- (id)initWithDataSource:(FileTreeDataSource *)ds url:(NSURL *)u;
|
||||
|
||||
- (NSURL *)URL;
|
||||
- (void)setURL:(NSURL *)url;
|
||||
|
||||
- (void)processPaths:(NSArray *)contents;
|
||||
|
||||
- (NSArray *)subpaths;
|
||||
- (void)setSubpaths:(NSArray *)s;
|
||||
|
||||
- (NSString *)display;
|
||||
- (void)setDisplay:(NSString *)s;
|
||||
|
||||
- (NSImage *)icon;
|
||||
|
||||
- (BOOL)isLeaf;
|
||||
|
||||
- (void)updatePath;
|
||||
|
||||
@end
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// Node.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/20/2006.
|
||||
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PathNode.h"
|
||||
|
||||
#import "CogAudio/AudioPlayer.h"
|
||||
|
||||
#import "FileTreeDataSource.h"
|
||||
|
||||
#import "ContainerNode.h"
|
||||
#import "DirectoryNode.h"
|
||||
#import "FileNode.h"
|
||||
#import "SmartFolderNode.h"
|
||||
|
||||
#import "Logging.h"
|
||||
|
||||
@implementation PathNode
|
||||
|
||||
// From http://developer.apple.com/documentation/Cocoa/Conceptual/LowLevelFileMgmt/Tasks/ResolvingAliases.html
|
||||
// Updated 2018-06-28
|
||||
NSURL *resolveAliases(NSURL *url) {
|
||||
CFErrorRef error;
|
||||
CFDataRef bookmarkRef = CFURLCreateBookmarkDataFromFile(kCFAllocatorDefault, (__bridge CFURLRef)url, &error);
|
||||
if(bookmarkRef) {
|
||||
Boolean isStale;
|
||||
CFURLRef urlRef = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, bookmarkRef, kCFURLBookmarkResolutionWithSecurityScope, NULL, NULL, &isStale, &error);
|
||||
CFRelease(bookmarkRef);
|
||||
|
||||
if(urlRef) {
|
||||
if(!isStale) {
|
||||
return (NSURL *)CFBridgingRelease(urlRef);
|
||||
} else {
|
||||
CFRelease(urlRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DLog(@"Not resolved");
|
||||
return url;
|
||||
}
|
||||
|
||||
- (id)initWithDataSource:(FileTreeDataSource *)ds url:(NSURL *)u {
|
||||
self = [super init];
|
||||
|
||||
if(self) {
|
||||
dataSource = ds;
|
||||
[self setURL:u];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)u {
|
||||
url = u;
|
||||
|
||||
display = [[NSFileManager defaultManager] displayNameAtPath:[u path]];
|
||||
|
||||
icon = [[NSWorkspace sharedWorkspace] iconForFile:[url path]];
|
||||
|
||||
[icon setSize:NSMakeSize(16.0, 16.0)];
|
||||
}
|
||||
|
||||
- (NSURL *)URL {
|
||||
return url;
|
||||
}
|
||||
|
||||
- (void)updatePath {
|
||||
}
|
||||
|
||||
- (void)processPaths:(NSArray *)contents {
|
||||
NSMutableArray *newSubpathsDirs = [[NSMutableArray alloc] init];
|
||||
NSMutableArray *newSubpaths = [[NSMutableArray alloc] init];
|
||||
|
||||
for(NSString *s in contents) {
|
||||
if([s characterAtIndex:0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSURL *u = [NSURL fileURLWithPath:s];
|
||||
NSString *displayName = [[NSFileManager defaultManager] displayNameAtPath:[u path]];
|
||||
|
||||
PathNode *newNode;
|
||||
|
||||
// DLog(@"Before: %@", u);
|
||||
u = resolveAliases(u);
|
||||
// DLog(@"After: %@", u);
|
||||
|
||||
BOOL isDir;
|
||||
|
||||
if([[s pathExtension] caseInsensitiveCompare:@"savedSearch"] == NSOrderedSame) {
|
||||
DLog(@"Smart folder!");
|
||||
newNode = [[SmartFolderNode alloc] initWithDataSource:dataSource url:u];
|
||||
isDir = NO;
|
||||
} else {
|
||||
[[NSFileManager defaultManager] fileExistsAtPath:[u path] isDirectory:&isDir];
|
||||
|
||||
if(!isDir && ![[AudioPlayer fileTypes] containsObject:[[u pathExtension] lowercaseString]]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isDir) {
|
||||
newNode = [[DirectoryNode alloc] initWithDataSource:dataSource url:u];
|
||||
} else if([[AudioPlayer containerTypes] containsObject:[[u pathExtension] lowercaseString]]) {
|
||||
newNode = [[ContainerNode alloc] initWithDataSource:dataSource url:u];
|
||||
} else {
|
||||
newNode = [[FileNode alloc] initWithDataSource:dataSource url:u];
|
||||
}
|
||||
}
|
||||
|
||||
[newNode setDisplay:displayName];
|
||||
|
||||
if(isDir)
|
||||
[newSubpathsDirs addObject:newNode];
|
||||
else
|
||||
[newSubpaths addObject:newNode];
|
||||
}
|
||||
|
||||
[newSubpathsDirs addObjectsFromArray:newSubpaths];
|
||||
[self setSubpaths:newSubpathsDirs];
|
||||
}
|
||||
|
||||
- (NSArray *)subpaths {
|
||||
if(subpaths == nil) {
|
||||
[self updatePath];
|
||||
}
|
||||
|
||||
return subpaths;
|
||||
}
|
||||
|
||||
- (void)setSubpaths:(NSArray *)s {
|
||||
subpaths = s;
|
||||
}
|
||||
|
||||
- (BOOL)isLeaf {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setDisplay:(NSString *)s {
|
||||
display = s;
|
||||
}
|
||||
|
||||
- (NSString *)display {
|
||||
return display;
|
||||
}
|
||||
|
||||
- (NSImage *)icon {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// PathWatcher.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/17/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
@interface PathWatcher : NSObject {
|
||||
FSEventStreamRef stream;
|
||||
FSEventStreamContext *context;
|
||||
|
||||
IBOutlet id delegate;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)d;
|
||||
- (id)delegate;
|
||||
|
||||
- (void)setPath:(NSString *)path; // Set the path to watch
|
||||
- (void)cleanUp;
|
||||
@end
|
||||
|
||||
@protocol PathWatcherDelegate
|
||||
|
||||
- (void)pathDidChange:(NSString *)path;
|
||||
|
||||
@end
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// PathWatcher.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/17/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PathWatcher.h"
|
||||
|
||||
static void myFSEventCallback(
|
||||
ConstFSEventStreamRef streamRef,
|
||||
void *clientCallBackInfo,
|
||||
size_t numEvents,
|
||||
void *eventPaths,
|
||||
const FSEventStreamEventFlags eventFlags[],
|
||||
const FSEventStreamEventId eventIds[]) {
|
||||
int i;
|
||||
char **paths = eventPaths;
|
||||
PathWatcher *pathWatcher = (__bridge PathWatcher *)clientCallBackInfo;
|
||||
|
||||
printf("Callback called\n");
|
||||
for(i = 0; i < numEvents; i++) {
|
||||
NSString *pathString = [[NSString alloc] initWithUTF8String:paths[i]];
|
||||
[[pathWatcher delegate] pathDidChange:pathString];
|
||||
}
|
||||
}
|
||||
|
||||
@implementation PathWatcher
|
||||
|
||||
- (void)cleanUp {
|
||||
if(stream) {
|
||||
FSEventStreamStop(stream);
|
||||
FSEventStreamInvalidate(stream);
|
||||
FSEventStreamRelease(stream);
|
||||
stream = NULL;
|
||||
}
|
||||
if(context) {
|
||||
free(context);
|
||||
context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPath:(NSString *)path {
|
||||
[self cleanUp];
|
||||
|
||||
if(!path) return;
|
||||
|
||||
// Create FSEvent stream
|
||||
NSArray *pathsToWatch = @[path];
|
||||
|
||||
context = (FSEventStreamContext *)malloc(sizeof(FSEventStreamContext));
|
||||
context->version = 0;
|
||||
context->info = (__bridge void *)self;
|
||||
context->retain = NULL;
|
||||
context->release = NULL;
|
||||
|
||||
// Create the stream, passing in a callback
|
||||
stream = FSEventStreamCreate(NULL,
|
||||
&myFSEventCallback,
|
||||
context,
|
||||
(__bridge CFArrayRef)pathsToWatch,
|
||||
kFSEventStreamEventIdSinceNow, // Or a previous event ID
|
||||
1.0, // latency in seconds
|
||||
kFSEventStreamCreateFlagNone // Watch this and all its subdirectories
|
||||
);
|
||||
|
||||
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
FSEventStreamStart(stream);
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)d {
|
||||
delegate = d;
|
||||
}
|
||||
- (id)delegate {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self cleanUp];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// SmartFolderNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 9/25/06.
|
||||
// Copyright 2006 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "PathNode.h"
|
||||
|
||||
@interface SmartFolderNode : PathNode {
|
||||
MDQueryRef _query;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// SmartFolderNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 9/25/06.
|
||||
// Copyright 2006 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SmartFolderNode.h"
|
||||
#import "DirectoryNode.h"
|
||||
#import "FileNode.h"
|
||||
#import "FileTreeDataSource.h"
|
||||
|
||||
#import "Logging.h"
|
||||
|
||||
@implementation SmartFolderNode
|
||||
|
||||
- (BOOL)isLeaf {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)updatePath {
|
||||
NSDictionary *doc = [NSDictionary dictionaryWithContentsOfFile:[url path]];
|
||||
NSString *rawQuery = [doc objectForKey:@"RawQuery"];
|
||||
NSArray *searchPaths = [[doc objectForKey:@"SearchCriteria"] objectForKey:@"CurrentFolderPath"];
|
||||
|
||||
// Ugh, Carbon from now on...
|
||||
MDQueryRef query = MDQueryCreate(kCFAllocatorDefault, (CFStringRef)rawQuery, NULL, NULL);
|
||||
_query = query;
|
||||
|
||||
MDQuerySetSearchScope(query, (CFArrayRef)searchPaths, 0);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryFinished:) name:(NSString *)kMDQueryDidFinishNotification object:(__bridge id)query];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryUpdate:) name:(NSString *)kMDQueryDidUpdateNotification object:(__bridge id)query];
|
||||
|
||||
DLog(@"Making query!");
|
||||
MDQueryExecute(query, kMDQueryWantsUpdates);
|
||||
|
||||
// Note: This is asynchronous!
|
||||
}
|
||||
|
||||
- (void)setSubpaths:(id)s {
|
||||
subpaths = s;
|
||||
}
|
||||
|
||||
- (unsigned int)countOfSubpaths {
|
||||
return (unsigned int)[[self subpaths] count];
|
||||
}
|
||||
|
||||
- (PathNode *)objectInSubpathsAtIndex:(unsigned int)index {
|
||||
return [[self subpaths] objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)queryFinished:(NSNotification *)notification {
|
||||
DLog(@"Query finished!");
|
||||
MDQueryRef query = (__bridge MDQueryRef)[notification object];
|
||||
|
||||
NSMutableArray *results = [NSMutableArray array];
|
||||
|
||||
MDQueryDisableUpdates(query);
|
||||
int c = (int)MDQueryGetResultCount(query);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < c; i++) {
|
||||
MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(query, i);
|
||||
|
||||
NSString *itemPath = (NSString *)CFBridgingRelease(MDItemCopyAttribute(item, kMDItemPath));
|
||||
|
||||
[results addObject:itemPath];
|
||||
}
|
||||
|
||||
MDQueryEnableUpdates(query);
|
||||
|
||||
DLog(@"Query update!");
|
||||
|
||||
[self processPaths:[results sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]];
|
||||
|
||||
[dataSource reloadPathNode:self];
|
||||
}
|
||||
|
||||
- (void)queryUpdate:(NSNotification *)notification {
|
||||
DLog(@"Query update!");
|
||||
[self queryFinished:notification];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
CFRelease(_query);
|
||||
}
|
||||
|
||||
@end
|
|
@ -88,6 +88,12 @@
|
|||
}
|
||||
|
||||
// Add other system paths to this setting
|
||||
NSString *fileTreePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"fileTreeRootURL"];
|
||||
if(fileTreePath && [fileTreePath length]) {
|
||||
// Append false name to dodge the directory/fragment trimmer
|
||||
[array addObject:[NSURL URLWithString:[fileTreePath stringByAppendingPathComponent:@"moo.mp3"]]];
|
||||
}
|
||||
|
||||
NSString *soundFontPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"soundFontPath"];
|
||||
if(soundFontPath && [soundFontPath length]) {
|
||||
[array addObject:[NSURL fileURLWithPath:soundFontPath]];
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// SideBarController.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 6/21/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PlaylistController.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface SideViewController : NSViewController {
|
||||
IBOutlet NSSplitView *splitView;
|
||||
IBOutlet NSView *mainView;
|
||||
IBOutlet NSView *firstResponder;
|
||||
}
|
||||
|
||||
- (IBAction)toggleSideView:(id)sender;
|
||||
- (IBAction)toggleVertical:(id)sender;
|
||||
|
||||
- (void)showSideView;
|
||||
- (void)hideSideView;
|
||||
- (BOOL)sideViewIsHidden;
|
||||
|
||||
- (void)setDividerPosition:(float)position;
|
||||
- (float)dividerPosition;
|
||||
|
||||
- (void)doAddToPlaylist:(NSArray *)urls origin:(URLOrigin)origin;
|
||||
|
||||
- (void)clear:(id)sender;
|
||||
|
||||
- (void)playPauseResume:(id)sender;
|
||||
|
||||
@end
|
|
@ -0,0 +1,183 @@
|
|||
//
|
||||
// SplitViewController.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 6/20/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SideViewController.h"
|
||||
|
||||
#import "Logging.h"
|
||||
|
||||
@implementation SideViewController
|
||||
|
||||
- (NSString *)showSideViewDefaultsKey {
|
||||
return [NSString stringWithFormat:@"%@ShowSideView", [self nibName]];
|
||||
}
|
||||
|
||||
- (NSString *)sideViewVerticalDefaultsKey {
|
||||
return [NSString stringWithFormat:@"%@SideViewVertical", [self nibName]];
|
||||
}
|
||||
|
||||
- (NSString *)sideViewDividerPositionDefaultsKey {
|
||||
return [NSString stringWithFormat:@"%@SideViewDividerPosition", [self nibName]];
|
||||
}
|
||||
|
||||
- (void)registerDefaults {
|
||||
NSMutableDictionary *userDefaultsValuesDict = [NSMutableDictionary dictionary];
|
||||
|
||||
[userDefaultsValuesDict setObject:@(YES) forKey:[self sideViewVerticalDefaultsKey]];
|
||||
[userDefaultsValuesDict setObject:@(NO) forKey:[self showSideViewDefaultsKey]];
|
||||
[userDefaultsValuesDict setObject:@(100.0) forKey:[self sideViewDividerPositionDefaultsKey]];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nib bundle:(NSBundle *)bundle {
|
||||
self = [super initWithNibName:nib bundle:bundle];
|
||||
if(self) {
|
||||
[self registerDefaults];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[splitView setVertical:[[NSUserDefaults standardUserDefaults] boolForKey:[self sideViewVerticalDefaultsKey]]];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:[self showSideViewDefaultsKey]]) {
|
||||
[self showSideView];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleSideView:(id)sender {
|
||||
// Show/hide current
|
||||
if([self sideViewIsHidden]) {
|
||||
[self showSideView];
|
||||
} else {
|
||||
[self hideSideView];
|
||||
}
|
||||
|
||||
[splitView adjustSubviews];
|
||||
}
|
||||
|
||||
- (IBAction)toggleVertical:(id)sender {
|
||||
[splitView setVertical:![splitView isVertical]];
|
||||
|
||||
if(![self sideViewIsHidden]) {
|
||||
[self showSideView];
|
||||
}
|
||||
|
||||
[splitView adjustSubviews];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[splitView isVertical] forKey:[self sideViewVerticalDefaultsKey]];
|
||||
}
|
||||
|
||||
- (void)showSideView {
|
||||
if([splitView isVertical]) {
|
||||
[splitView setSubviews:@[[self view], mainView]];
|
||||
} else {
|
||||
[splitView setSubviews:@[mainView, [self view]]];
|
||||
}
|
||||
|
||||
[self setDividerPosition:[[NSUserDefaults standardUserDefaults] floatForKey:[self sideViewDividerPositionDefaultsKey]]];
|
||||
|
||||
[[[self view] window] makeFirstResponder:firstResponder];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:[self showSideViewDefaultsKey]];
|
||||
}
|
||||
|
||||
- (void)hideSideView {
|
||||
[splitView setSubviews:@[mainView]];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:[self showSideViewDefaultsKey]];
|
||||
|
||||
[[mainView window] makeFirstResponder:mainView];
|
||||
}
|
||||
|
||||
- (BOOL)sideViewIsHidden {
|
||||
return ([[splitView subviews] count] == 1);
|
||||
}
|
||||
|
||||
- (BOOL)splitView:(NSSplitView *)aSplitView canCollapseSubview:(NSView *)subview {
|
||||
return (subview != mainView);
|
||||
}
|
||||
|
||||
- (BOOL)splitView:(NSSplitView *)aSplitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex {
|
||||
return (subview != mainView);
|
||||
}
|
||||
|
||||
- (void)splitViewDidResizeSubviews:(NSNotification *)aNotification {
|
||||
// Update default
|
||||
if(![self sideViewIsHidden]) {
|
||||
[[NSUserDefaults standardUserDefaults] setFloat:[self dividerPosition] forKey:[self sideViewDividerPositionDefaultsKey]];
|
||||
DLog(@"DIVIDER POSITION: %f", [self dividerPosition]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
|
||||
if([self sideViewIsHidden]) {
|
||||
[splitView adjustSubviews];
|
||||
} else {
|
||||
CGFloat dividerThickness = [splitView dividerThickness];
|
||||
|
||||
NSRect sideRect = [[self view] frame];
|
||||
NSRect mainRect = [mainView frame];
|
||||
|
||||
NSRect newFrame = [splitView frame];
|
||||
|
||||
if([splitView isVertical]) {
|
||||
sideRect.size.width = [[NSUserDefaults standardUserDefaults] floatForKey:[self sideViewDividerPositionDefaultsKey]];
|
||||
sideRect.size.height = newFrame.size.height;
|
||||
sideRect.origin = NSMakePoint(0, 0);
|
||||
|
||||
mainRect.size.width = newFrame.size.width - sideRect.size.width - dividerThickness;
|
||||
mainRect.size.height = newFrame.size.height;
|
||||
mainRect.origin.x = sideRect.size.width + dividerThickness;
|
||||
} else {
|
||||
sideRect.size.height = [[NSUserDefaults standardUserDefaults] floatForKey:[self sideViewDividerPositionDefaultsKey]];
|
||||
sideRect.size.width = newFrame.size.width;
|
||||
|
||||
mainRect.origin = NSMakePoint(0, 0);
|
||||
mainRect.size.width = newFrame.size.width;
|
||||
mainRect.size.height = newFrame.size.height - sideRect.size.height - dividerThickness;
|
||||
|
||||
sideRect.origin.y = mainRect.size.height + dividerThickness;
|
||||
}
|
||||
|
||||
[[self view] setFrame:sideRect];
|
||||
[mainView setFrame:mainRect];
|
||||
}
|
||||
}
|
||||
|
||||
- (float)dividerPosition {
|
||||
if([splitView isVertical]) {
|
||||
return [[self view] frame].size.width;
|
||||
}
|
||||
|
||||
return [[self view] frame].size.height;
|
||||
}
|
||||
|
||||
- (void)setDividerPosition:(float)position {
|
||||
float actualPosition = position;
|
||||
if(![splitView isVertical]) {
|
||||
actualPosition = ([splitView frame].size.height - position);
|
||||
}
|
||||
|
||||
[splitView adjustSubviews];
|
||||
[splitView setPosition:actualPosition ofDividerAtIndex:0];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setFloat:position forKey:[self sideViewDividerPositionDefaultsKey]];
|
||||
}
|
||||
|
||||
// placeholders, implemented by subclass
|
||||
- (void)doAddToPlaylist:(NSArray *)urls origin:(URLOrigin)origin {
|
||||
}
|
||||
|
||||
- (void)clear:(id)sender {
|
||||
}
|
||||
|
||||
- (void)playPauseResume:(id)sender {
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "71"; */
|
||||
"71.title" = "Text Cell";
|
||||
|
||||
/* Class = "NSMenu"; title = "Menu"; ObjectID = "110"; */
|
||||
"110.title" = "Menu";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show in Finder"; ObjectID = "112"; */
|
||||
"112.title" = "Show in Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add to Playlist"; ObjectID = "119"; */
|
||||
"119.title" = "Add to Playlist";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Set as Root"; ObjectID = "124"; */
|
||||
"124.title" = "Set as Root";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Set as Playlist"; ObjectID = "129"; */
|
||||
"129.title" = "Set as Playlist";
|
||||
|
||||
/* Class = "NSBox"; title = "Box"; ObjectID = "147"; */
|
||||
"147.title" = "Box";
|
|
@ -335,6 +335,12 @@
|
|||
/* Class = "NSToolbarItem"; paletteLabel = "Info Inspector"; ObjectID = "1629"; */
|
||||
"1629.paletteLabel" = "Info Inspector";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "File Tree"; ObjectID = "1630"; */
|
||||
"1630.label" = "File Tree";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "File Tree"; ObjectID = "1630"; */
|
||||
"1630.paletteLabel" = "File Tree";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Shuffle"; ObjectID = "1636"; */
|
||||
"1636.label" = "Shuffle";
|
||||
|
||||
|
@ -473,6 +479,9 @@
|
|||
/* Class = "CocoaBindingsConnection"; ibShadowedIsNilPlaceholder = "Not Playing"; ObjectID = "2085"; */
|
||||
"2085.ibShadowedIsNilPlaceholder" = "Not Playing";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Toggle File Tree Orientation"; ObjectID = "2160"; */
|
||||
"2160.title" = "Toggle File Tree Orientation";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Information"; ObjectID = "2212"; */
|
||||
"2212.title" = "Information";
|
||||
|
||||
|
@ -539,6 +548,9 @@
|
|||
/* Class = "CocoaBindingsConnection"; ibShadowedNotApplicablePlaceholder = "Cog"; ObjectID = "2374"; */
|
||||
"2374.ibShadowedNotApplicablePlaceholder" = "Cog";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show File Tree"; ObjectID = "2417"; */
|
||||
"2417.title" = "Show File Tree";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Info Inspector"; ObjectID = "2429"; */
|
||||
"2429.label" = "Info Inspector";
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "71"; */
|
||||
"71.title" = "Text Cell";
|
||||
|
||||
/* Class = "NSMenu"; title = "Menu"; ObjectID = "110"; */
|
||||
"110.title" = "Menu";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show in Finder"; ObjectID = "112"; */
|
||||
"112.title" = "Show in Finder";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Add to Playlist"; ObjectID = "119"; */
|
||||
"119.title" = "Add to Playlist";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Set as Root"; ObjectID = "124"; */
|
||||
"124.title" = "Set as Root";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Set as Playlist"; ObjectID = "129"; */
|
||||
"129.title" = "Set as Playlist";
|
||||
|
||||
/* Class = "NSBox"; title = "Box"; ObjectID = "147"; */
|
||||
"147.title" = "Box";
|
|
@ -335,6 +335,12 @@
|
|||
/* Class = "NSToolbarItem"; paletteLabel = "Info Inspector"; ObjectID = "1629"; */
|
||||
"1629.paletteLabel" = "Info Inspector";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "File Tree"; ObjectID = "1630"; */
|
||||
"1630.label" = "File Tree";
|
||||
|
||||
/* Class = "NSToolbarItem"; paletteLabel = "File Tree"; ObjectID = "1630"; */
|
||||
"1630.paletteLabel" = "File Tree";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Shuffle"; ObjectID = "1636"; */
|
||||
"1636.label" = "Shuffle";
|
||||
|
||||
|
@ -473,6 +479,9 @@
|
|||
/* Class = "CocoaBindingsConnection"; ibShadowedIsNilPlaceholder = "Not Playing"; ObjectID = "2085"; */
|
||||
"2085.ibShadowedIsNilPlaceholder" = "Not Playing";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Toggle File Tree Orientation"; ObjectID = "2160"; */
|
||||
"2160.title" = "Toggle File Tree Orientation";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Information"; ObjectID = "2212"; */
|
||||
"2212.title" = "Information";
|
||||
|
||||
|
@ -539,6 +548,9 @@
|
|||
/* Class = "CocoaBindingsConnection"; ibShadowedNotApplicablePlaceholder = "Cog"; ObjectID = "2374"; */
|
||||
"2374.ibShadowedNotApplicablePlaceholder" = "Cog";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Show File Tree"; ObjectID = "2417"; */
|
||||
"2417.title" = "Show File Tree";
|
||||
|
||||
/* Class = "NSToolbarItem"; label = "Info Inspector"; ObjectID = "2429"; */
|
||||
"2429.label" = "Info Inspector";
|
||||
|
||||
|
|
Loading…
Reference in New Issue