TableViewPlayground: Using View-Based NSTableView and NSOutlineView: Version 3.0, 2017-04-14

Upgraded for macOS 10.12 SDK, addressed deprecated API usage, modern Obj-C syntax.

The TableViewPlayground demonstrates using the view based NSTableView and NSOutlineView. Four different samples are shown. First, a HUD window with an NSTableView that completely uses bindings to display sample windows to create. Second, a basic View Based TableView implementation is shown using delegate and dataSource methods. Third, a complex TableView example based on the AnimatedTableView demo application. Finally, a complex NSOutlineView demo that mixes bindings and a dataSource to get the job done.

Signed-off-by: Liu Lantao <liulantao@gmail.com>
This commit is contained in:
Liu Lantao 2018-02-10 13:06:18 +08:00
parent f4d3340bbc
commit ba9d4a31c7
No known key found for this signature in database
GPG Key ID: BF35AA0CD375679D
41 changed files with 4733 additions and 0 deletions

View File

@ -0,0 +1,42 @@
Sample code project: TableViewPlayground: Using View-Based NSTableView and NSOutlineView
Version: 3.0
IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2017 Apple Inc. All Rights Reserved.

View File

@ -0,0 +1,56 @@
# TableViewPlayground
## Description
This example demonstrates the View Based TableView. The demo focuses on three areas:
1. Basic TableView, 2. Complex TableView, 3. Complex OutlineView.
The same model is shared between the Complex TableView and OutlineView classes.
## Requirements
### Build Requirements
macOS 10.12 SDK or later
### Runtime Requirements
macOS 10.12 or later
## Packing List
ATDesktopEntity.h/.m:
The basic sample model for the application.
ATApplicationController.h/.m:
Main controller for the application.
ATBasicTableViewWindowController.h/m:
Basic controller implementation for a basic View Based TableView.
ATColorTableController.h/.m:
Controller for the color table popup used in the ATComplextTableViewController example
ATColorView.h/.m:
Simple view that adds an animatable background color.
ATComplexOutlineController.h/.m:
Complex Outline View example controller.
ATComplexTableViewController.h/.m:
Complex Table View example controller.
ATObjectTableRowView.h/.m:
Extends NSTableRowView by adding an objectValue for the row.
ATSampleWindowRowView.h/.m:
Extends NSTableRowView by adding custom background drawing.
ATTableCellView.h:
Extends NSTableCellView primarily for adding outlets to be hooked up in IB.
English.proj:
Localized NIBs.
Copyright (C) 2010-2017 Apple Inc. All rights reserved.

View File

@ -0,0 +1,472 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
53868F921E5E2812002FF831 /* ATMainWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53868F911E5E2812002FF831 /* ATMainWindowController.m */; };
53DE7FDE1E5BAFEF00E7FCF0 /* ATApplicationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FDD1E5BAFEE00E7FCF0 /* ATApplicationController.m */; };
53DE7FE11E5BAFFE00E7FCF0 /* ATSampleWindowRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FE01E5BAFFE00E7FCF0 /* ATSampleWindowRowView.m */; };
53DE7FE41E5BB01A00E7FCF0 /* ATDesktopEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FE31E5BB01A00E7FCF0 /* ATDesktopEntity.m */; };
53DE7FE71E5BB02100E7FCF0 /* ATColorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FE61E5BB02100E7FCF0 /* ATColorView.m */; };
53DE7FEA1E5BB04000E7FCF0 /* ATBasicTableViewWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53DE7FE81E5BB04000E7FCF0 /* ATBasicTableViewWindow.xib */; };
53DE7FED1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FEC1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.m */; };
53DE7FF21E5BB05800E7FCF0 /* ATColorTable.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53DE7FEE1E5BB05800E7FCF0 /* ATColorTable.xib */; };
53DE7FF31E5BB05800E7FCF0 /* ATComplexTableViewWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53DE7FF01E5BB05800E7FCF0 /* ATComplexTableViewWindow.xib */; };
53DE7FF61E5BB06800E7FCF0 /* ATTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FF51E5BB06800E7FCF0 /* ATTableCellView.m */; };
53DE7FF91E5BB07300E7FCF0 /* ATComplexTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FF81E5BB07300E7FCF0 /* ATComplexTableViewController.m */; };
53DE7FFC1E5BB08000E7FCF0 /* ATColorTableController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FFB1E5BB08000E7FCF0 /* ATColorTableController.m */; };
53DE7FFF1E5BB08900E7FCF0 /* ATObjectTableRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE7FFE1E5BB08900E7FCF0 /* ATObjectTableRowView.m */; };
53DE80021E5BB09400E7FCF0 /* ATComplexOutlineController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE80011E5BB09400E7FCF0 /* ATComplexOutlineController.m */; };
53DE80051E5BB09C00E7FCF0 /* ATComplexOutlineWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53DE80031E5BB09C00E7FCF0 /* ATComplexOutlineWindow.xib */; };
53DE80081E5BB0A700E7FCF0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DE80061E5BB0A700E7FCF0 /* main.m */; };
53DE800B1E5BB0AD00E7FCF0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53DE80091E5BB0AD00E7FCF0 /* MainMenu.xib */; };
53DE800D1E5BB0BA00E7FCF0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53DE800C1E5BB0BA00E7FCF0 /* Images.xcassets */; };
53DE80121E5BB0F700E7FCF0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53DE80101E5BB0F700E7FCF0 /* InfoPlist.strings */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
530AD8E61E5BB48C00FAC825 /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = "<group>"; };
53868F901E5E2812002FF831 /* ATMainWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATMainWindowController.h; path = TableViewPlayground/ATMainWindowController.h; sourceTree = "<group>"; };
53868F911E5E2812002FF831 /* ATMainWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATMainWindowController.m; path = TableViewPlayground/ATMainWindowController.m; sourceTree = "<group>"; };
53D763661E5BB714003C72C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = TableViewPlayground/Base.lproj/ATBasicTableViewWindow.xib; sourceTree = "<group>"; };
53D763671E5BB714003C72C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = TableViewPlayground/Base.lproj/ATColorTable.xib; sourceTree = "<group>"; };
53D763681E5BB714003C72C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = TableViewPlayground/Base.lproj/ATComplexTableViewWindow.xib; sourceTree = "<group>"; };
53D763691E5BB714003C72C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = TableViewPlayground/Base.lproj/ATComplexOutlineWindow.xib; sourceTree = "<group>"; };
53D7636A1E5BB714003C72C2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = TableViewPlayground/Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
53DE7FDC1E5BAFEE00E7FCF0 /* ATApplicationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATApplicationController.h; path = TableViewPlayground/ATApplicationController.h; sourceTree = "<group>"; };
53DE7FDD1E5BAFEE00E7FCF0 /* ATApplicationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATApplicationController.m; path = TableViewPlayground/ATApplicationController.m; sourceTree = "<group>"; };
53DE7FDF1E5BAFFE00E7FCF0 /* ATSampleWindowRowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATSampleWindowRowView.h; path = TableViewPlayground/ATSampleWindowRowView.h; sourceTree = "<group>"; };
53DE7FE01E5BAFFE00E7FCF0 /* ATSampleWindowRowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATSampleWindowRowView.m; path = TableViewPlayground/ATSampleWindowRowView.m; sourceTree = "<group>"; };
53DE7FE21E5BB01A00E7FCF0 /* ATDesktopEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATDesktopEntity.h; path = TableViewPlayground/ATDesktopEntity.h; sourceTree = "<group>"; };
53DE7FE31E5BB01A00E7FCF0 /* ATDesktopEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATDesktopEntity.m; path = TableViewPlayground/ATDesktopEntity.m; sourceTree = "<group>"; };
53DE7FE51E5BB02100E7FCF0 /* ATColorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATColorView.h; path = TableViewPlayground/ATColorView.h; sourceTree = "<group>"; };
53DE7FE61E5BB02100E7FCF0 /* ATColorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATColorView.m; path = TableViewPlayground/ATColorView.m; sourceTree = "<group>"; };
53DE7FEB1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATBasicTableViewWindowController.h; path = TableViewPlayground/ATBasicTableViewWindowController.h; sourceTree = "<group>"; };
53DE7FEC1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATBasicTableViewWindowController.m; path = TableViewPlayground/ATBasicTableViewWindowController.m; sourceTree = "<group>"; };
53DE7FF41E5BB06800E7FCF0 /* ATTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATTableCellView.h; path = TableViewPlayground/ATTableCellView.h; sourceTree = "<group>"; };
53DE7FF51E5BB06800E7FCF0 /* ATTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATTableCellView.m; path = TableViewPlayground/ATTableCellView.m; sourceTree = "<group>"; };
53DE7FF71E5BB07300E7FCF0 /* ATComplexTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATComplexTableViewController.h; path = TableViewPlayground/ATComplexTableViewController.h; sourceTree = "<group>"; };
53DE7FF81E5BB07300E7FCF0 /* ATComplexTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATComplexTableViewController.m; path = TableViewPlayground/ATComplexTableViewController.m; sourceTree = "<group>"; };
53DE7FFA1E5BB08000E7FCF0 /* ATColorTableController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATColorTableController.h; path = TableViewPlayground/ATColorTableController.h; sourceTree = "<group>"; };
53DE7FFB1E5BB08000E7FCF0 /* ATColorTableController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATColorTableController.m; path = TableViewPlayground/ATColorTableController.m; sourceTree = "<group>"; };
53DE7FFD1E5BB08900E7FCF0 /* ATObjectTableRowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATObjectTableRowView.h; path = TableViewPlayground/ATObjectTableRowView.h; sourceTree = "<group>"; };
53DE7FFE1E5BB08900E7FCF0 /* ATObjectTableRowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATObjectTableRowView.m; path = TableViewPlayground/ATObjectTableRowView.m; sourceTree = "<group>"; };
53DE80001E5BB09400E7FCF0 /* ATComplexOutlineController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATComplexOutlineController.h; path = TableViewPlayground/ATComplexOutlineController.h; sourceTree = "<group>"; };
53DE80011E5BB09400E7FCF0 /* ATComplexOutlineController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ATComplexOutlineController.m; path = TableViewPlayground/ATComplexOutlineController.m; sourceTree = "<group>"; };
53DE80061E5BB0A700E7FCF0 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = TableViewPlayground/main.m; sourceTree = "<group>"; };
53DE800C1E5BB0BA00E7FCF0 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = TableViewPlayground/Images.xcassets; sourceTree = "<group>"; };
53DE800E1E5BB0EC00E7FCF0 /* TableViewPlayground-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "TableViewPlayground-Info.plist"; path = "TableViewPlayground/TableViewPlayground-Info.plist"; sourceTree = "<group>"; };
53DE80111E5BB0F700E7FCF0 /* English */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = English; path = TableViewPlayground/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* TableViewPlayground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TableViewPlayground.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8D11072E0486CEB800E47090 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
19C28FACFE9D520D11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8D1107320486CEB800E47090 /* TableViewPlayground.app */,
);
name = Products;
sourceTree = "<group>";
};
29B97314FDCFA39411CA2CEA /* AnimatedTableView */ = {
isa = PBXGroup;
children = (
530AD8E61E5BB48C00FAC825 /* ReadMe.md */,
53FBD5D91E689198005E7EA6 /* Application */,
53FBD5DA1E6891B9005E7EA6 /* MainWindow */,
9DAE33031097571400BB95A7 /* Basic TableView Window */,
9DD1743B108F7332006E27B5 /* Complex TableView Window */,
9DD17742108F7E25006E27B5 /* Complex OutlineView Window */,
9DDE9BA30FA1255F00BE4471 /* Model */,
9DDE9BA40FA1257400BE4471 /* Shared Views */,
29B97317FDCFA39411CA2CEA /* Resources */,
19C28FACFE9D520D11CA2CBB /* Products */,
);
name = AnimatedTableView;
sourceTree = "<group>";
};
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
53DE800C1E5BB0BA00E7FCF0 /* Images.xcassets */,
53DE80091E5BB0AD00E7FCF0 /* MainMenu.xib */,
53DE800E1E5BB0EC00E7FCF0 /* TableViewPlayground-Info.plist */,
53DE80101E5BB0F700E7FCF0 /* InfoPlist.strings */,
);
name = Resources;
sourceTree = "<group>";
};
53FBD5D91E689198005E7EA6 /* Application */ = {
isa = PBXGroup;
children = (
53DE80061E5BB0A700E7FCF0 /* main.m */,
53DE7FDC1E5BAFEE00E7FCF0 /* ATApplicationController.h */,
53DE7FDD1E5BAFEE00E7FCF0 /* ATApplicationController.m */,
);
name = Application;
sourceTree = "<group>";
};
53FBD5DA1E6891B9005E7EA6 /* MainWindow */ = {
isa = PBXGroup;
children = (
53868F901E5E2812002FF831 /* ATMainWindowController.h */,
53868F911E5E2812002FF831 /* ATMainWindowController.m */,
53DE7FDF1E5BAFFE00E7FCF0 /* ATSampleWindowRowView.h */,
53DE7FE01E5BAFFE00E7FCF0 /* ATSampleWindowRowView.m */,
);
name = MainWindow;
sourceTree = "<group>";
};
9DAE33031097571400BB95A7 /* Basic TableView Window */ = {
isa = PBXGroup;
children = (
53DE7FEB1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.h */,
53DE7FEC1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.m */,
9DAE3307109758AB00BB95A7 /* Resources */,
);
name = "Basic TableView Window";
sourceTree = "<group>";
};
9DAE3307109758AB00BB95A7 /* Resources */ = {
isa = PBXGroup;
children = (
53DE7FE81E5BB04000E7FCF0 /* ATBasicTableViewWindow.xib */,
);
name = Resources;
sourceTree = "<group>";
};
9DD1743B108F7332006E27B5 /* Complex TableView Window */ = {
isa = PBXGroup;
children = (
53DE7FF71E5BB07300E7FCF0 /* ATComplexTableViewController.h */,
53DE7FF81E5BB07300E7FCF0 /* ATComplexTableViewController.m */,
53DE7FF41E5BB06800E7FCF0 /* ATTableCellView.h */,
53DE7FF51E5BB06800E7FCF0 /* ATTableCellView.m */,
53DE7FFA1E5BB08000E7FCF0 /* ATColorTableController.h */,
53DE7FFB1E5BB08000E7FCF0 /* ATColorTableController.m */,
53DE7FFD1E5BB08900E7FCF0 /* ATObjectTableRowView.h */,
53DE7FFE1E5BB08900E7FCF0 /* ATObjectTableRowView.m */,
9DD17500108F750D006E27B5 /* Resources */,
);
name = "Complex TableView Window";
sourceTree = "<group>";
};
9DD17500108F750D006E27B5 /* Resources */ = {
isa = PBXGroup;
children = (
53DE7FEE1E5BB05800E7FCF0 /* ATColorTable.xib */,
53DE7FF01E5BB05800E7FCF0 /* ATComplexTableViewWindow.xib */,
);
name = Resources;
sourceTree = "<group>";
};
9DD17742108F7E25006E27B5 /* Complex OutlineView Window */ = {
isa = PBXGroup;
children = (
53DE80001E5BB09400E7FCF0 /* ATComplexOutlineController.h */,
53DE80011E5BB09400E7FCF0 /* ATComplexOutlineController.m */,
9DD17743108F7E3B006E27B5 /* Resources */,
);
name = "Complex OutlineView Window";
sourceTree = "<group>";
};
9DD17743108F7E3B006E27B5 /* Resources */ = {
isa = PBXGroup;
children = (
53DE80031E5BB09C00E7FCF0 /* ATComplexOutlineWindow.xib */,
);
name = Resources;
sourceTree = "<group>";
};
9DDE9BA30FA1255F00BE4471 /* Model */ = {
isa = PBXGroup;
children = (
53DE7FE21E5BB01A00E7FCF0 /* ATDesktopEntity.h */,
53DE7FE31E5BB01A00E7FCF0 /* ATDesktopEntity.m */,
);
name = Model;
sourceTree = "<group>";
};
9DDE9BA40FA1257400BE4471 /* Shared Views */ = {
isa = PBXGroup;
children = (
53DE7FE51E5BB02100E7FCF0 /* ATColorView.h */,
53DE7FE61E5BB02100E7FCF0 /* ATColorView.m */,
);
name = "Shared Views";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8D1107260486CEB800E47090 /* TableViewPlayground */ = {
isa = PBXNativeTarget;
buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "TableViewPlayground" */;
buildPhases = (
8D1107290486CEB800E47090 /* Resources */,
8D11072C0486CEB800E47090 /* Sources */,
8D11072E0486CEB800E47090 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = TableViewPlayground;
productInstallPath = "$(HOME)/Applications";
productName = AnimatedTableView;
productReference = 8D1107320486CEB800E47090 /* TableViewPlayground.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0830;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TableViewPlayground" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Base,
);
mainGroup = 29B97314FDCFA39411CA2CEA /* AnimatedTableView */;
projectDirPath = "";
projectRoot = "";
targets = (
8D1107260486CEB800E47090 /* TableViewPlayground */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8D1107290486CEB800E47090 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
53DE80121E5BB0F700E7FCF0 /* InfoPlist.strings in Resources */,
53DE800D1E5BB0BA00E7FCF0 /* Images.xcassets in Resources */,
53DE7FEA1E5BB04000E7FCF0 /* ATBasicTableViewWindow.xib in Resources */,
53DE7FF21E5BB05800E7FCF0 /* ATColorTable.xib in Resources */,
53DE7FF31E5BB05800E7FCF0 /* ATComplexTableViewWindow.xib in Resources */,
53DE80051E5BB09C00E7FCF0 /* ATComplexOutlineWindow.xib in Resources */,
53DE800B1E5BB0AD00E7FCF0 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D11072C0486CEB800E47090 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
53DE7FDE1E5BAFEF00E7FCF0 /* ATApplicationController.m in Sources */,
53DE7FF61E5BB06800E7FCF0 /* ATTableCellView.m in Sources */,
53DE7FFF1E5BB08900E7FCF0 /* ATObjectTableRowView.m in Sources */,
53DE7FFC1E5BB08000E7FCF0 /* ATColorTableController.m in Sources */,
53DE7FE41E5BB01A00E7FCF0 /* ATDesktopEntity.m in Sources */,
53868F921E5E2812002FF831 /* ATMainWindowController.m in Sources */,
53DE7FED1E5BB04B00E7FCF0 /* ATBasicTableViewWindowController.m in Sources */,
53DE7FE71E5BB02100E7FCF0 /* ATColorView.m in Sources */,
53DE7FF91E5BB07300E7FCF0 /* ATComplexTableViewController.m in Sources */,
53DE7FE11E5BAFFE00E7FCF0 /* ATSampleWindowRowView.m in Sources */,
53DE80081E5BB0A700E7FCF0 /* main.m in Sources */,
53DE80021E5BB09400E7FCF0 /* ATComplexOutlineController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
53DE7FE81E5BB04000E7FCF0 /* ATBasicTableViewWindow.xib */ = {
isa = PBXVariantGroup;
children = (
53D763661E5BB714003C72C2 /* Base */,
);
name = ATBasicTableViewWindow.xib;
sourceTree = "<group>";
};
53DE7FEE1E5BB05800E7FCF0 /* ATColorTable.xib */ = {
isa = PBXVariantGroup;
children = (
53D763671E5BB714003C72C2 /* Base */,
);
name = ATColorTable.xib;
sourceTree = "<group>";
};
53DE7FF01E5BB05800E7FCF0 /* ATComplexTableViewWindow.xib */ = {
isa = PBXVariantGroup;
children = (
53D763681E5BB714003C72C2 /* Base */,
);
name = ATComplexTableViewWindow.xib;
sourceTree = "<group>";
};
53DE80031E5BB09C00E7FCF0 /* ATComplexOutlineWindow.xib */ = {
isa = PBXVariantGroup;
children = (
53D763691E5BB714003C72C2 /* Base */,
);
name = ATComplexOutlineWindow.xib;
sourceTree = "<group>";
};
53DE80091E5BB0AD00E7FCF0 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
53D7636A1E5BB714003C72C2 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
53DE80101E5BB0F700E7FCF0 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
53DE80111E5BB0F700E7FCF0 /* English */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
INFOPLIST_FILE = "TableViewPlayground/TableViewPlayground-Info.plist";
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.TableViewPlayground";
PRODUCT_NAME = TableViewPlayground;
SDKROOT = macosx;
};
name = Debug;
};
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
INFOPLIST_FILE = "TableViewPlayground/TableViewPlayground-Info.plist";
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_BUNDLE_IDENTIFIER = "com.example.apple-samplecode.TableViewPlayground";
PRODUCT_NAME = TableViewPlayground;
SDKROOT = macosx;
};
name = Release;
};
C01FCF4F08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
ONLY_ACTIVE_ARCH = YES;
};
name = Debug;
};
C01FCF5008A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "TableViewPlayground" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C01FCF4B08A954540054247B /* Debug */,
C01FCF4C08A954540054247B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TableViewPlayground" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C01FCF4F08A954540054247B /* Debug */,
C01FCF5008A954540054247B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
}

View File

@ -0,0 +1,13 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The main demo application controller. This class is the delegate for the main NSApp instance. This class manages the windows that are open, and allows the user to create a new one with the 'Available Sample Windows' table view. Bindings are used in the 'Available Sample Windows' table for the content. The TableView is bound to the tableContents, which is an array of NSDictionary objects that contain the information to disply.
*/
@import Cocoa;
@interface ATApplicationController : NSObject
@end

View File

@ -0,0 +1,82 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The main demo application controller. This class is the delegate for the main NSApp instance. This class manages the windows that are open, and allows the user to create a new one with the 'Available Sample Windows' table view. Bindings are used in the 'Available Sample Windows' table for the content. The TableView is bound to the tableContents, which is an array of NSDictionary objects that contain the information to disply.
*/
#import "ATApplicationController.h"
#import "ATMainWindowController.h"
#import "ATComplexTableViewController.h"
#import "ATComplexOutlineController.h"
#import "ATBasicTableViewWindowController.h"
#pragma mark -
@interface ATApplicationController ()
@property (strong) NSMutableArray *windowControllers;
@property (strong) IBOutlet ATMainWindowController *mainWindowController;
@end
/* Notes on how this demo window was created:
In ATBasicTableViewWindow.xib in IB:
The nib has the "File's Owner" Class Identity set to ATBasicTableViewWindowController (this class).
The NSTableView in the nib has the 'delegate' and 'dataSource' outlets set to the "File's Owner" (this class).
The first NSTableColumn in the NSTableView has the 'identifier' set to "MainCell".
The second NSTableColumn in the NSTableView has the 'identifier' set to "SizeCell".
The NSTableView has two reuse identifier assocations: "MainCell" and "SizeCell" are both associated with the nib ATBasicTableViewCells.xib.
The "File's Owner" tableView outlet was set to the nib in the window.
In ATBasicTableViewCells.xib in IB:
The nib has the "File's Owner" Class Identity set to ATBasicTableViewWindowController (this class).
Two cells were added to the nib.
The identifier for the first is set to "MainCell", and the second "SizeCell".
Each NSTableCellView already had the 'textField' outlet properly set to the NSTextField in the cell by IB when the NSTableCellView wsa created.
*/
#pragma mark -
@implementation ATApplicationController
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
// Create our three windows on startup.
[self newWindowWithControllerClass:[ATBasicTableViewWindowController class]];
[self newWindowWithControllerClass:[ATComplexTableViewController class]];
[self newWindowWithControllerClass:[ATComplexOutlineController class]];
}
- (void)newWindowWithControllerClass:(Class)c {
NSWindowController *controller = [[c alloc] init];
if (_windowControllers == nil) {
_windowControllers = [NSMutableArray array];
}
[self.windowControllers addObject:controller];
[controller showWindow:self];
}
- (void)awakeFromNib {
[super awakeFromNib];
// Show our main window that creates additional windows.
[self.mainWindowController showWindow:self];
// Observe all windows closing so we can remove them from our array.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowClosed:) name:NSWindowWillCloseNotification object:nil];
}
- (void)windowClosed:(NSNotification *)note {
NSWindow *window = note.object;
for (NSWindowController *winController in self.windowControllers) {
if (winController.window == window) {
[self.windowControllers removeObject:winController];
break;
}
}
}
@end

View File

@ -0,0 +1,13 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Demonstrates the most basic dataSource/delegate implementation of a View Based NSTableView.
*/
@import Cocoa;
@interface ATBasicTableViewWindowController : NSWindowController
@end

View File

@ -0,0 +1,151 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Demonstrates the most basic dataSource/delegate implementation of a View Based NSTableView.
*/
#import "ATBasicTableViewWindowController.h"
@interface ATBasicTableViewWindowController () <NSTableViewDelegate, NSTableViewDataSource>
// An array of dictionaries that contain the contents to display
@property (strong) NSMutableArray *tableContents;
@property (weak) IBOutlet NSTableView *tableView;
@end
/* Notes on how this demo window was created:
In ATBasicTableViewWindow.xib in IB:
The nib has the "File's Owner" Class Identity set to ATBasicTableViewWindowController (this class).
The NSTableView in the nib has the 'delegate' and 'dataSource' outlets set to the "File's Owner" (this class).
The first NSTableColumn in the NSTableView has the 'identifier' set to "MainCell".
The second NSTableColumn in the NSTableView has the 'identifier' set to "SizeCell".
The NSTableView has two reuse identifier assocations: "MainCell" and "SizeCell" are both associated with the nib ATBasicTableViewCells.xib.
The "File's Owner" _tableView outlet was set to the nib in the window.
In ATBasicTableViewCells.xib in IB:
The nib has the "File's Owner" Class Identity set to ATBasicTableViewWindowController (this class).
Two cells were added to the nib.
The identifier for the first is set to "MainCell", and the second "SizeCell".
Each NSTableCellView already had the 'textField' outlet properly set to the NSTextField in the cell by IB when the NSTableCellView was created.
*/
@implementation ATBasicTableViewWindowController
- (NSString *)windowNibName {
return @"ATBasicTableViewWindow";
}
- (void)windowDidLoad {
[super windowDidLoad];
NSArray *tableData = @[@"NSQuickLookTemplate",
@"NSBluetoothTemplate",
@"NSIChatTheaterTemplate",
@"NSSlideshowTemplate",
@"NSActionTemplate",
@"NSSmartBadgeTemplate",
@"NSIconViewTemplate",
@"NSListViewTemplate",
@"NSColumnViewTemplate",
@"NSFlowViewTemplate",
@"NSPathTemplate",
@"NSInvalidDataFreestandingTemplate",
@"NSLockLockedTemplate",
@"NSLockUnlockedTemplate",
@"NSGoRightTemplate",
@"NSGoLeftTemplate",
@"NSRightFacingTriangleTemplate",
@"NSLeftFacingTriangleTemplate",
@"NSAddTemplate",
@"NSRemoveTemplate",
@"NSRevealFreestandingTemplate",
@"NSFollowLinkFreestandingTemplate",
@"NSEnterFullScreenTemplate",
@"NSExitFullScreenTemplate",
@"NSStopProgressTemplate",
@"NSStopProgressFreestandingTemplate",
@"NSRefreshTemplate",
@"NSRefreshFreestandingTemplate",
@"NSBonjour",
@"NSComputer",
@"NSFolderBurnable",
@"NSFolderSmart",
@"NSFolder",
@"NSNetwork",
@"NSMobileMe",
@"NSMultipleDocuments",
@"NSUserAccounts",
@"NSPreferencesGeneral",
@"NSAdvanced",
@"NSInfo",
@"NSFontPanel",
@"NSColorPanel",
@"NSUser",
@"NSUserGroup",
@"NSEveryone",
@"NSUserGuest",
@"NSMenuOnStateTemplate",
@"NSMenuMixedStateTemplate",
@"NSApplicationIcon",
@"NSTrashEmpty",
@"NSTrashFull",
@"NSHomeTemplate",
@"NSBookmarksTemplate",
@"NSCaution",
@"NSStatusAvailable",
@"NSStatusPartiallyAvailable",
@"NSStatusUnavailable",
@"NSStatusNone"];
// Load up our sample data.
_tableContents = [NSMutableArray array];
// Our model consists of an array of dictionaries with Name/Image key pairs.
for (NSString *templateImageItem in tableData) {
NSImage *image = [NSImage imageNamed:templateImageItem];
NSDictionary *dictionary = @{@"Name": templateImageItem, @"Image": image};
[self.tableContents addObject:dictionary];
}
[self.tableView reloadData];
}
// The only essential/required tableview dataSource method.
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.tableContents.count;
}
// This method is optional if you use bindings to provide the data.
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
// Group our "model" object, which is a dictionary.
NSDictionary *dictionary = self.tableContents[row];
// In IB the tableColumn has the identifier set to the same string as the keys in our dictionary.
NSString *identifier = tableColumn.identifier;
if ([identifier isEqualToString:@"MainCell"]) {
// We pass us as the owner so we can setup target/actions into this main controller object.
NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self];
// Then setup properties on the cellView based on the column.
cellView.textField.stringValue = dictionary[@"Name"];
cellView.imageView.objectValue = dictionary[@"Image"];
return cellView;
} else if ([identifier isEqualToString:@"SizeCell"]) {
NSTextField *textField = [tableView makeViewWithIdentifier:identifier owner:self];
NSImage *image = dictionary[@"Image"];
NSSize size = image ? image.size : NSZeroSize;
NSString *sizeString = [NSString stringWithFormat:@"%.0fx%.0f", size.width, size.height];
textField.objectValue = sizeString;
return textField;
} else {
NSAssert1(NO, @"Unhandled table column identifier %@", identifier);
}
return nil;
}
@end

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A controller used by the ATColorTableController to edit the color property.
*/
@import Cocoa;
@protocol ATColorTableControllerDelegate;
@interface ATColorTableController : NSViewController {
id <ATColorTableControllerDelegate> __unsafe_unretained _delegate;
}
+ (ATColorTableController *)sharedColorTableController;
- (void)editColor:(NSColor *)color withPositioningView:(NSView *)view;
@property (weak, readonly) NSColor *selectedColor;
@property (weak, readonly) NSString *selectedColorName;
@property(unsafe_unretained) id <ATColorTableControllerDelegate> delegate;
@end
#pragma mark -
@protocol ATColorTableControllerDelegate <NSObject>
@optional
- (void)colorTableController:(ATColorTableController *)controller didChooseColor:(NSColor *)color named:(NSString *)colorName;
@end

View File

@ -0,0 +1,136 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A controller used by the ATColorTableController to edit the color property.
*/
#import "ATColorTableController.h"
#import "ATTableCellView.h"
#import "ATColorView.h"
@interface ATColorTableController () <NSTableViewDelegate, NSTableViewDataSource, NSPopoverDelegate>
@property (weak) IBOutlet NSTableView *tableColorList;
@property (strong) NSColorList *colorList;
@property (strong) NSArray *colorNames;
@property (strong) NSPopover *popover;
@end
#pragma mark -
@implementation ATColorTableController
@dynamic selectedColor, selectedColorName;
+ (ATColorTableController *)sharedColorTableController {
static ATColorTableController *gSharedColorTableController = nil;
if (gSharedColorTableController == nil) {
gSharedColorTableController = [[[self class] alloc] initWithNibName:@"ATColorTable" bundle:[NSBundle bundleForClass:[self class]]];
}
return gSharedColorTableController;
}
- (void)loadView {
[super loadView];
_colorList = [NSColorList colorListNamed:@"Crayons"];
_colorNames = self.colorList.allKeys;
self.tableColorList.intercellSpacing = NSMakeSize(3, 3);
self.tableColorList.target = self;
self.tableColorList.action = @selector(tableViewAction:);
}
- (NSColor *)selectedColor {
NSString *name = self.selectedColorName;
if (name != nil) {
return [self.colorList colorWithKey:name];
} else {
return nil;
}
}
- (NSString *)selectedColorName {
if (self.tableColorList.selectedRow != -1) {
return self.colorNames[self.tableColorList.selectedRow];
} else {
return nil;
}
}
- (void)_selectColor:(NSColor *)color {
// Search for that color in our list.
NSInteger row = 0;
for (NSString *name in self.colorNames) {
NSColor *colorInList = [self.colorList colorWithKey:name];
if ([color isEqual:colorInList]) {
break;
}
row++;
}
// This is done in an animated fashion
if (row != -1) {
[self.tableColorList scrollRowToVisible:row];
[[self.tableColorList animator] selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
} else {
[self.tableColorList scrollRowToVisible:0];
[[self.tableColorList animator] selectRowIndexes:[NSIndexSet indexSet] byExtendingSelection:NO];
}
}
- (void)makePopoverIfNeeded {
if (self.popover == nil) {
// Create and setup our window.
_popover = [[NSPopover alloc] init];
// The popover retains us and we retain the popover. We drop the popover whenever it is closed to avoid a cycle.
self.popover.contentViewController = self;
self.popover.behavior = NSPopoverBehaviorTransient;
self.popover.delegate = self;
}
}
- (void)editColor:(NSColor *)color withPositioningView:(NSView *)positioningView {
[self makePopoverIfNeeded];
[self _selectColor:color];
[self.popover showRelativeToRect:positioningView.bounds ofView:positioningView preferredEdge:NSMinYEdge];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.colorNames.count;
}
- (id)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSString *name = self.colorNames[row];
NSColor *color = [self.colorList colorWithKey:name];
// In IB, the TableColumn's identifier is set to "Automatic".
// The ATTableCellView's is also set to "Automatic". IB then keeps the two in sync,
// and we don't have to worry about setting the identifier.
//
ATTableCellView *result = [tableView makeViewWithIdentifier:tableColumn.identifier owner:nil];
result.colorView.backgroundColor = color;
result.colorView.drawBorder = YES;
result.subTitleTextField.stringValue = name;
return result;
}
- (void)tableViewAction:(id)sender {
[self.popover close];
if ([self.delegate respondsToSelector:@selector(colorTableController:didChooseColor:named:)]) {
[self.delegate colorTableController:self didChooseColor:self.selectedColor named:self.selectedColorName];
}
}
- (void)popoverDidClose:(NSNotification *)notification {
// Free the popover to avoid a cycle.
// We could also just break the contentViewController property, and reset it when we show the popover.
_popover = nil;
}
@end

View File

@ -0,0 +1,16 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A basic NSView subclass that supports having an animatable background color (NOTE: the animation only works when the view is layer backed).
*/
@import Cocoa;
@interface ATColorView : NSControl
@property (strong, nonatomic) NSColor *backgroundColor;
@property BOOL drawBorder;
@end

View File

@ -0,0 +1,51 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A basic NSView subclass that supports having an animatable background color (NOTE: the animation only works when the view is layer backed).
*/
#import "ATColorView.h"
@import Quartz; // for CABasicAnimation
@implementation ATColorView
+ (id)defaultAnimationForKey:(NSString *)key {
if ([key isEqualToString:@"backgroundColor"]) {
return [CABasicAnimation animation];
}
return [super defaultAnimationForKey:key];
}
- (void)setBackgroundColor:(NSColor *)value {
if (_backgroundColor != value) {
_backgroundColor = value;
self.layer.backgroundColor = _backgroundColor.CGColor;
[self setNeedsDisplay:YES];
}
}
- (void)drawRect:(NSRect)r {
NSColor *color = self.backgroundColor;
if (color) {
[color set];
NSRectFill(r);
}
if (self.drawBorder) {
[[NSColor lightGrayColor] set];
NSFrameRectWithWidth(self.bounds, 1.0);
}
if (self.window.firstResponder == self) {
NSSetFocusRingStyle(NSFocusRingOnly);
NSRectFill(self.bounds);
}
}
+ (Class)cellClass {
// The cell is a container for the target/action
return [NSActionCell class];
}
@end

View File

@ -0,0 +1,13 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The main controller for the "Complex Outline View" example window.
*/
@import Cocoa;
@interface ATComplexOutlineController : NSWindowController
@end

View File

@ -0,0 +1,443 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The main controller for the "Complex Outline View" example window.
*/
#import "ATComplexOutlineController.h"
#import "ATTableCellView.h"
#import "ATColorView.h"
#import "ATDesktopEntity.h"
@interface ATComplexOutlineController ()
@property (strong) ATDesktopFolderEntity *rootContents;
@property (weak) IBOutlet NSOutlineView *outlineView;
@property (weak) IBOutlet NSPathControl *pathCtrlRootDirectory;
@property (strong) IBOutlet NSDateFormatter *sharedDateFormatter;
@property (strong) ATDesktopEntity *itemBeingDragged;
@end
#pragma mark -
@implementation ATComplexOutlineController
- (NSString *)windowNibName {
return @"ATComplexOutlineWindow";
}
- (void)windowDidLoad {
[super windowDidLoad];
// Setup our content to be the contents of the Desktop Pictures folder.
NSURL *picturesURL =
[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSLocalDomainMask].lastObject;
picturesURL = [picturesURL URLByAppendingPathComponent:@"Desktop Pictures"];
_rootContents = [[ATDesktopFolderEntity alloc] initWithFileURL:picturesURL];
[self.outlineView reloadData];
[self.outlineView registerForDraggedTypes:@[(id)kUTTypeURL]];
[self.outlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
}
#pragma mark - NSOutlineView
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
if (item == nil) {
return self.rootContents.children.count;
} else if ([item isKindOfClass:[ATDesktopFolderEntity class]]) {
return ((ATDesktopFolderEntity *)item).children.count;
} else {
return 0;
}
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
if (item == nil) {
return (self.rootContents.children)[index];
} else {
return (((ATDesktopFolderEntity *)item).children)[index];
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
return [item isKindOfClass:[ATDesktopFolderEntity class]];
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
// Every regular view uses bindings to the item. The "Date Cell" needs to have the date extracted from the fileURL
if ([tableColumn.identifier isEqualToString:@"DateCell"]) {
id dateValue;
if ([[item fileURL] getResourceValue:&dateValue forKey:NSURLContentModificationDateKey error:nil]) {
return dateValue;
} else {
return nil;
}
}
return item;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
return [item isKindOfClass:[ATDesktopFolderEntity class]];
}
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
if ([item isKindOfClass:[ATDesktopFolderEntity class]]) {
// Everything is setup in bindings
return [outlineView makeViewWithIdentifier:@"GroupCell" owner:self];
} else {
NSView *result = [outlineView makeViewWithIdentifier:tableColumn.identifier owner:self];
if ([result isKindOfClass:[ATTableCellView class]]) {
ATTableCellView *cellView = (ATTableCellView *)result;
// setup the color; we can't do this in bindings
cellView.colorView.drawBorder = YES;
cellView.colorView.backgroundColor = [item fillColor];
}
// Use a shared date formatter on the DateCell for better performance. Otherwise, it is encoded in every NSTextField
if ([tableColumn.identifier isEqualToString:@"DateCell"]) {
[(id)result setFormatter:self.sharedDateFormatter];
}
return result;
}
return nil;
}
#pragma mark - Drag and Drop
- (id <NSPasteboardWriting>)outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item {
return (id <NSPasteboardWriting>)item;
}
- (void)outlineView:(NSOutlineView *)outlineView draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint forItems:(NSArray *)draggedItems {
_itemBeingDragged = nil;
// If only one item is being dragged, mark it so we can reorder it with a special pboard indicator
if (draggedItems.count == 1) {
_itemBeingDragged = draggedItems.lastObject;
}
}
- (NSDictionary *)_pasteboardReadingOptions {
// Only file urls that contain images or folders
NSMutableArray *fileTypes = [NSMutableArray arrayWithObject:(id)kUTTypeFolder];
[fileTypes addObjectsFromArray:[NSImage imageTypes]];
NSDictionary *options = @{NSPasteboardURLReadingFileURLsOnlyKey: @YES, NSPasteboardURLReadingContentsConformToTypesKey: fileTypes};
return options;
}
/* When validating the contents of the pasteboard, it is best practice to use -canReadObjectForClasses:arrayWithObject:options: since it is possible for it to avoid reading and creating objects for every pasteboard item.
*/
- (BOOL)_containsAcceptableURLsFromPasteboard:(NSPasteboard *)draggingPasteboard {
return [draggingPasteboard canReadObjectForClasses:@[[NSURL class]] options:[self _pasteboardReadingOptions]];
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index {
// Only let dropping on the entire table or a folder
if (item == nil || [item isKindOfClass:[ATDesktopFolderEntity class]]) {
// If the sender is ourselves, then we accept it as a move or copy, depending on the modifier key
if ([info draggingSource] == outlineView) {
BOOL isCopy = [info draggingSourceOperationMask] == NSDragOperationCopy;
if (isCopy) {
info.animatesToDestination = YES;
return NSDragOperationCopy;
} else {
if (self.itemBeingDragged) {
// We have a single item being dragged to move; validate if we can move it or not
// A move is only valid if the target isn't a child of the thing being dragged. We validate that now
id itemWalker = item;
while (itemWalker) {
if (itemWalker == self.itemBeingDragged) {
return NSDragOperationNone; // Can't do it!
}
itemWalker = [outlineView parentForItem:itemWalker];
}
return NSDragOperationMove;
} else {
// For multiple items, we do a copy and don't allow moving
info.animatesToDestination = YES;
return NSDragOperationCopy;
}
}
} else {
// Only accept drops that have at least one URL on the pasteboard which contains an image or a folder
if ([self _containsAcceptableURLsFromPasteboard:[info draggingPasteboard]]) {
info.animatesToDestination = YES;
return NSDragOperationCopy;
}
}
}
return NSDragOperationNone;
}
// Multiple item dragging support. Implementation of this method is required to change the drag images into what we want them to look like when over our view
- (void)outlineView:(NSOutlineView *)outlineView updateDraggingItemsForDrag:(id <NSDraggingInfo>)draggingInfo {
if ([draggingInfo draggingSource] != outlineView) {
// The source isn't us, so update the drag images
// We will be doing an insertion; update the dragging items to have an appropriate image. We also iterate over generic pasteboard items, and set the imageComponentsProvider to nil so they will fade out.
NSArray *classes = @[[ATDesktopEntity class], [NSPasteboardItem class]];
// Create a copied temporary cell to draw to images
NSTableColumn *tableColumn = self.outlineView.outlineTableColumn;
// Create a new cell frame based on the basic attributes
NSRect cellFrame = NSMakeRect(0, 0, tableColumn.width, outlineView.rowHeight);
// Subtract out the intercellSpacing from the width only. The rowHeight is sans-spacing
cellFrame.size.width -= outlineView.intercellSpacing.width;
// Grab a basic view to use for creating sample images and data; we will reuse it for each dragged item
ATTableCellView *tableCellView = [outlineView makeViewWithIdentifier:tableColumn.identifier owner:self];
__block NSInteger validCount = 0;
[draggingInfo enumerateDraggingItemsWithOptions:0 forView:self.outlineView classes:classes searchOptions:@{} usingBlock:^(NSDraggingItem *draggingItem, NSInteger index, BOOL *stop) {
if ([draggingItem.item isKindOfClass:[ATDesktopEntity class]]) {
ATDesktopEntity *entity = (ATDesktopEntity *)draggingItem.item;
draggingItem.draggingFrame = cellFrame;
draggingItem.imageComponentsProvider = ^(void) {
// Force the image to be generated right now, instead of lazily doing it
if ([entity isKindOfClass:[ATDesktopImageEntity class]]) {
((ATDesktopImageEntity *)entity).image = [[NSImage alloc] initByReferencingURL:entity.fileURL];
}
// Setup the cell with this temporary data
tableCellView.objectValue = entity; // This is what bindings normally does for us. Our sub-views are bound to this value.
tableCellView.frame = cellFrame;
// Ask the cell view for the image components from that cell
return tableCellView.draggingImageComponents;
};
validCount++;
} else {
// Non-valid item (a generic NSPasteboardItem).
// Make the drag images go away
draggingItem.imageComponentsProvider = nil;
}
}];
draggingInfo.numberOfValidItemsForDrop = validCount;
}
}
- (void)_performInsertWithDragInfo:(id <NSDraggingInfo>)info parentItem:(ATDesktopFolderEntity *)destinationFolderEntity childIndex:(NSInteger)childIndex {
// NSOutlineView's root is nil
id outlineParentItem = destinationFolderEntity == self.rootContents ? nil : destinationFolderEntity;
NSInteger outlineColumnIndex = [self.outlineView.tableColumns indexOfObject:self.outlineView.outlineTableColumn];
// Enumerate all items dropped on us and create new model objects for them
NSArray *classes = @[[ATDesktopEntity class]];
__block NSInteger insertionIndex = childIndex;
[info enumerateDraggingItemsWithOptions:0 forView:self.outlineView classes:classes searchOptions:[self _pasteboardReadingOptions] usingBlock:^(NSDraggingItem *draggingItem, NSInteger index, BOOL *stop) {
// the item is our new model object -- created by the classes via the pasteboard reading support
ATDesktopEntity *entity = (ATDesktopEntity *)draggingItem.item;
// Add it to the model
[destinationFolderEntity.children insertObject:entity atIndex:insertionIndex];
// Tell the outlineview of the change
[self.outlineView insertItemsAtIndexes:[NSIndexSet indexSetWithIndex:insertionIndex] inParent:outlineParentItem withAnimation:NSTableViewAnimationEffectGap];
// Update the final frame of the dragging item
NSInteger row = [self.outlineView rowForItem:entity];
draggingItem.draggingFrame = [self.outlineView frameOfCellAtColumn:outlineColumnIndex row:row];
// Insert all children one after another
insertionIndex++;
}];
}
- (void)_performDragReorderWithDragInfo:(id <NSDraggingInfo>)info parentItem:(ATDesktopFolderEntity *)destinationFolderEntity childIndex:(NSInteger)childIndex {
ATDesktopFolderEntity *oldParent = [self.outlineView parentForItem:self.itemBeingDragged];
if (oldParent == nil) oldParent = self.rootContents;
NSInteger fromIndex = [oldParent.children indexOfObject:self.itemBeingDragged];
[oldParent.children removeObjectAtIndex:fromIndex];
if (oldParent == destinationFolderEntity) {
// Consider the item being deleted before it is being inserted.
// This is because we are inserting *before* childIndex, and *not* after it (which is what the move API does).
if (fromIndex < childIndex) {
childIndex--;
}
}
[destinationFolderEntity.children insertObject:self.itemBeingDragged atIndex:childIndex];
// NSOutlineView doesn't have a way of setting the root item
if (oldParent == self.rootContents) oldParent = nil;
if (destinationFolderEntity == self.rootContents) destinationFolderEntity = nil;
[self.outlineView moveItemAtIndex:fromIndex inParent:oldParent toIndex:childIndex inParent:destinationFolderEntity];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(ATDesktopEntity *)item childIndex:(NSInteger)childIndex {
ATDesktopFolderEntity *destinationFolderEntity = nil;
if (item == nil) {
destinationFolderEntity = self.rootContents;
} else if ([item isKindOfClass:[ATDesktopFolderEntity class]]) {
destinationFolderEntity = (ATDesktopFolderEntity *)item;
} else {
NSAssert(NO, @"Internal error: expecting a folder entity for dropping onto!");
}
// If it was a drop "on", then we add it at the start
if (childIndex == NSOutlineViewDropOnItemIndex) {
childIndex = 0;
}
[self.outlineView beginUpdates];
// Are we copying the data or moving something?
if (self.itemBeingDragged == nil || [info draggingSourceOperationMask] == NSDragOperationCopy) {
// Yes, this is an insert from the pasteboard (even if it is a copy of itemBeingDragged)
[self _performInsertWithDragInfo:info parentItem:destinationFolderEntity childIndex:childIndex];
} else {
[self _performDragReorderWithDragInfo:info parentItem:destinationFolderEntity childIndex:childIndex];
}
[self.outlineView endUpdates];
_itemBeingDragged = nil;
return YES;
}
- (void)_removeItemAtRow:(NSInteger)row {
id item = [self.outlineView itemAtRow:row];
ATDesktopFolderEntity *parent = (ATDesktopFolderEntity *)[self.outlineView parentForItem:item];
if (parent == nil) {
parent = self.rootContents;
}
NSInteger indexInParent = [parent.children indexOfObject:item];
[parent.children removeObjectAtIndex:indexInParent];
if (parent == self.rootContents) {
parent = nil;
}
[self.outlineView removeItemsAtIndexes:[NSIndexSet indexSetWithIndex:indexInParent]
inParent:parent
withAnimation:NSTableViewAnimationEffectFade | NSTableViewAnimationSlideLeft];
}
#pragma mark - Actions
- (IBAction)pathCtrlValueChanged:(id)sender {
NSURL *url = self.pathCtrlRootDirectory.objectValue;
self.rootContents = [[ATDesktopFolderEntity alloc] initWithFileURL:url];
[self.outlineView reloadData];
}
- (IBAction)btnDeleteRowClicked:(id)sender {
NSInteger row = [self.outlineView rowForView:sender];
if (row != -1) {
// Take care of the case of the user clicking on a row that was in the middle of being deleted
[self _removeItemAtRow:row];
}
}
- (IBAction)btnDeletedSelectedRowsClicked:(id)sender {
[self.outlineView beginUpdates];
[self.outlineView.selectedRowIndexes enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger index, BOOL *stop) {
[self _removeItemAtRow:index];
}];
[self.outlineView endUpdates];
}
- (IBAction)btnInCellClicked:(id)sender {
NSInteger row = [self.outlineView rowForView:sender];
ATDesktopEntity *entity = [self.outlineView itemAtRow:row];
[[NSWorkspace sharedWorkspace] selectFile:entity.fileURL.path inFileViewerRootedAtPath:@""];
}
- (IBAction)btnDemoMove:(id)sender {
// Move the selected item down one
NSInteger selectedRow = self.outlineView.selectedRow;
if (selectedRow != -1) {
id item = [self.outlineView itemAtRow:selectedRow]; // retain the item as we are removing it from our array
// Grab the parent for this item
ATDesktopFolderEntity *parent = [self.outlineView parentForItem:item];
// The parent may be nil, so we use the root if it is
if (parent == nil) {
parent = self.rootContents;
}
// Find out where it currently is
NSInteger indexInParent = [parent.children indexOfObject:item];
// Then remove it
[parent.children removeObjectAtIndex:indexInParent];
// Move it one index further down, or back to the start, if it would already be at the end.
NSUInteger targetIndexInParent = indexInParent + 1;
if (targetIndexInParent > parent.children.count) {
targetIndexInParent = 0; // back to the start
}
[parent.children insertObject:item atIndex:targetIndexInParent];
// Tell outlineview about our change to our model; but of course, it uses 'nil' as the root item so we have to move back to nil if we were using the root as the parent.
if (parent == self.rootContents) {
parent = nil;
}
[self.outlineView moveItemAtIndex:indexInParent inParent:parent toIndex:targetIndexInParent inParent:parent];
} else {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = NSLocalizedString(@"Select something!", @"");
alert.informativeText = NSLocalizedString(@"Select a row for an example of moving it down...", @"");
[alert addButtonWithTitle:NSLocalizedString(@"OK", @"")];
[alert runModal];
}
}
- (IBAction)btnDemoBatchedMoves:(id)sender {
// Swap all the children of the first two expandable items
ATDesktopFolderEntity *firstParent = nil;
ATDesktopFolderEntity *secondParent = nil;
for (ATDesktopEntity *entity in _rootContents.children) {
if ([entity isKindOfClass:[ATDesktopFolderEntity class]]) {
ATDesktopFolderEntity *folderEntity = (ATDesktopFolderEntity *)entity;
if (firstParent == nil) {
firstParent = folderEntity;
} else {
secondParent = folderEntity;
break;
}
}
}
if (firstParent && secondParent) {
[self.outlineView beginUpdates];
// Move all the first children to the second array
for (NSUInteger i = 0; i < firstParent.children.count; i++) {
[self.outlineView moveItemAtIndex:0 inParent:firstParent toIndex:i inParent:secondParent];
}
// Move all the children from the second to the first. We have to account for the fact that we just moved all the first items to this one.
NSInteger childrenOffset = firstParent.children.count;
for (NSUInteger i = 0; i < secondParent.children.count; i++) {
[self.outlineView moveItemAtIndex:childrenOffset inParent:secondParent toIndex:i inParent:firstParent];
}
// Do the changes on our model, and tell the OV we are done
NSMutableArray *firstParentChildren = firstParent.children;
firstParent.children = secondParent.children;
secondParent.children = firstParentChildren;
[self.outlineView endUpdates];
} else {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = NSLocalizedString(@"Expand something!", @"");
alert.informativeText = NSLocalizedString(@"Couldn't find two parents to do demo move with. Expand some items!", @"");
[alert addButtonWithTitle:NSLocalizedString(@"OK", @"")];
[alert runModal];
}
}
- (IBAction)chkbxFloatGroupRowsClicked:(id)sender {
BOOL checked = ((NSButton *)sender).state == 1;
self.outlineView.floatsGroupRows = checked;
}
- (IBAction)clrWellChanged:(id)sender {
NSColor *color = [sender color];
self.outlineView.backgroundColor = color;
}
@end

View File

@ -0,0 +1,13 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The basic controller for the demo app. An instance exists inside the MainMenu.xib file.
*/
@import Cocoa;
@interface ATComplexTableViewController : NSWindowController
@end

View File

@ -0,0 +1,670 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The basic controller for the demo app. An instance exists inside the MainMenu.xib file.
*/
#import "ATComplexTableViewController.h"
#import "ATColorView.h"
#import "ATTableCellView.h"
#import "ATObjectTableRowView.h"
#import "ATDesktopEntity.h"
#import "ATColorTableController.h"
@interface ATComplexTableViewController () <NSTableViewDelegate, NSTableViewDataSource, ATColorTableControllerDelegate, NSSplitViewDelegate>
@property (weak) IBOutlet NSImageView *imageViewMain;
@property (weak) IBOutlet ATColorView *colorViewMain;
@property (strong) NSMutableArray *observedVisibleItems;
@property (strong) NSTimer *animationDoneTimer;
@property (strong) NSWindow *windowForAnimation;
@property (weak) IBOutlet NSSplitView *mainSplitView;
@property (weak) IBOutlet NSTableView *tableViewMain;
@property (strong) IBOutlet NSImageView *imageViewForTransition;
@property (strong) NSMutableArray *tableContents;
@property (assign) BOOL useSmallRowHeight;
@property (assign) NSInteger rowForEditingColor;
@property (weak) IBOutlet NSTextField *txtFldFromRow;
@property (weak) IBOutlet NSTextField *txtFldToRow;
@property (weak) IBOutlet NSTextField *txtFldRowToEdit;
@end
#pragma mark -
@implementation ATComplexTableViewController
- (void)dealloc {
// Stop any observations that we may have.
for (ATDesktopEntity *imageEntity in self.observedVisibleItems) {
if ([imageEntity isKindOfClass:[ATDesktopImageEntity class]]) {
[imageEntity removeObserver:self forKeyPath:ATEntityPropertyNamedThumbnailImage];
}
}
}
- (NSString *)windowNibName {
return @"ATComplexTableViewWindow";
}
- (void)windowDidLoad {
[super windowDidLoad];
// Setup our content to be the contents of the Desktop Pictures folder.
NSURL *picturesURL =
[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSLocalDomainMask].lastObject;
picturesURL = [picturesURL URLByAppendingPathComponent:@"Desktop Pictures"];
ATDesktopFolderEntity *primaryFolder = [[ATDesktopFolderEntity alloc] initWithFileURL:picturesURL];
// Create a flat array of ATDesktopFolderEntity and ATDesktopImageEntity objects to display.
_tableContents = [NSMutableArray array];
// We first do a pass over the children and add all the images under the "Desktop Pictures" category.
[self.tableContents addObject:primaryFolder];
for (ATDesktopEntity *entity in primaryFolder.children) {
if ([entity isKindOfClass:[ATDesktopImageEntity class]]) {
[self.tableContents addObject:entity];
}
}
// Then do another pass through and add all the folders - including their children.
// A recursive loop could be used too, but we want to only go one level deep.
//
for (ATDesktopEntity *entity in primaryFolder.children) {
if ([entity isKindOfClass:[ATDesktopFolderEntity class]]) {
[self.tableContents addObject:entity];
ATDesktopFolderEntity *subFolder = (ATDesktopFolderEntity *)entity;
for (ATDesktopEntity *subFolderChildEntity in subFolder.children) {
if ([subFolderChildEntity isKindOfClass:[ATDesktopImageEntity class]]) {
[self.tableContents addObject:subFolderChildEntity];
}
}
}
}
self.colorViewMain.drawBorder = YES;
self.colorViewMain.backgroundColor = [NSColor whiteColor];
// Initialize the main image view to our current desktop background.
NSImage *initialImage = [[NSImage alloc] initByReferencingURL:[[NSWorkspace sharedWorkspace] desktopImageURLForScreen:[NSScreen mainScreen]]];
self.imageViewMain.image = initialImage;
self.tableViewMain.doubleAction = @selector(tblvwDoubleClick:);
self.tableViewMain.target = self;
[self.tableViewMain reloadData];
// Allow drags to go everywhere.
[self.tableViewMain setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
}
- (ATDesktopEntity *)entityForRow:(NSInteger)row {
return (ATDesktopEntity *)self.tableContents[row];
}
- (ATDesktopImageEntity *)imageEntityForRow:(NSInteger)row {
id result = row != -1 ? self.tableContents[row] : nil;
if ([result isKindOfClass:[ATDesktopImageEntity class]]) {
return result;
}
return nil;
}
- (void)reloadRowForEntity:(id)object {
NSInteger row = [self.tableContents indexOfObject:object];
if (row != NSNotFound) {
ATDesktopImageEntity *entity = [self imageEntityForRow:row];
ATTableCellView *cellView = [self.tableViewMain viewAtColumn:0 row:row makeIfNecessary:NO];
if (cellView) {
// Fade the imageView in, and fade the progress indicator out.
[NSAnimationContext beginGrouping];
[NSAnimationContext currentContext].duration = 0.8;
cellView.imageView.alphaValue = 0;
cellView.imageView.image = entity.thumbnailImage;
cellView.imageView.hidden = NO;
cellView.imageView.animator.alphaValue = 1.0;
cellView.progessIndicator.hidden = YES;
[NSAnimationContext endGrouping];
}
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:ATEntityPropertyNamedThumbnailImage]) {
// Find the row and reload it.
// Note that KVO notifications may be sent from a background thread (in this case, we know they will be)
// We should only update the UI on the main thread, and in addition,
// we use NSRunLoopCommonModes to make sure the UI updates when a modal window is up.
//
[self performSelectorOnMainThread:@selector(reloadRowForEntity:)
withObject:object
waitUntilDone:NO
modes:@[NSRunLoopCommonModes]];
}
}
#pragma mark - NSTableViewDataSource
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.tableContents.count;
}
- (id <NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row {
// Support for us being a dragging source.
return [self entityForRow:row];
}
#pragma mark - NSTableViewDelegate
- (void)tableView:(NSTableView *)tableView didRemoveRowView:(ATObjectTableRowView *)rowView forRow:(NSInteger)row {
// Stop observing visible things.
ATDesktopImageEntity *imageEntity = rowView.objectValue;
NSInteger index = imageEntity ? [self.observedVisibleItems indexOfObject:imageEntity] : NSNotFound;
if (index != NSNotFound) {
[imageEntity removeObserver:self forKeyPath:ATEntityPropertyNamedThumbnailImage];
[self.observedVisibleItems removeObjectAtIndex:index];
}
}
- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row {
// Make the row view keep track of our main model object.
ATObjectTableRowView *result = [[ATObjectTableRowView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
result.objectValue = [self entityForRow:row];
return result;
}
// We want to make "group rows" for the folders.
- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row {
if ([[self entityForRow:row] isKindOfClass:[ATDesktopFolderEntity class]]) {
return YES;
} else {
return NO;
}
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
ATDesktopEntity *entity = [self entityForRow:row];
if ([entity isKindOfClass:[ATDesktopFolderEntity class]]) {
NSTextField *textField = [tableView makeViewWithIdentifier:@"TextCell" owner:self];
textField.stringValue = entity.title;
return textField;
} else {
ATTableCellView *cellView = [tableView makeViewWithIdentifier:@"MainCell" owner:self];
ATDesktopImageEntity *imageEntity = (ATDesktopImageEntity *)entity;
cellView.textField.stringValue = entity.title;
cellView.subTitleTextField.stringValue = imageEntity.fillColorName;
cellView.colorView.backgroundColor = imageEntity.fillColor;
cellView.colorView.drawBorder = YES;
// Use KVO to observe for changes of the thumbnail image.
if (self.observedVisibleItems == nil) {
_observedVisibleItems = [NSMutableArray new];
}
if (![self.observedVisibleItems containsObject:entity]) {
[imageEntity addObserver:self forKeyPath:ATEntityPropertyNamedThumbnailImage options:0 context:nil];
[imageEntity loadImage];
[self.observedVisibleItems addObject:imageEntity];
}
// Hide/show progress based on the thumbnail image being loaded or not.
if (imageEntity.thumbnailImage == nil) {
cellView.progessIndicator.hidden = NO;
[cellView.progessIndicator startAnimation:nil];
cellView.imageView.hidden = YES;
} else {
cellView.imageView.image = imageEntity.thumbnailImage;
}
// Size/hide things based on the row size.
[cellView layoutViewsForSmallSize:self.useSmallRowHeight animated:NO];
return cellView;
}
}
// We make the "group rows" have the standard height, while all other image rows have a larger height.
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
if ([[self entityForRow:row] isKindOfClass:[ATDesktopFolderEntity class]]) {
return tableView.rowHeight;
} else {
return self.useSmallRowHeight ? 30.0 : 75.0;
}
}
- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes {
// We don't want to change the selection if the user clicked in the fill color area.
NSInteger row = tableView.clickedRow;
if (row != -1 && ![self tableView:tableView isGroupRow:row]) {
ATTableCellView *cellView = [self.tableViewMain viewAtColumn:0 row:row makeIfNecessary:NO];
if (cellView) {
// Use hit testing to see if is a color view; if so, don't let it change the selection.
NSPoint windowPoint = NSApp.currentEvent.locationInWindow;
NSPoint point = [cellView.superview convertPoint:windowPoint fromView:nil];
NSView *view = [cellView hitTest:point];
if ([view isKindOfClass:[ATColorView class]]) {
// Don't allow the selection change.
return tableView.selectedRowIndexes;
}
}
}
return proposedSelectionIndexes;
}
#pragma mark - Table Animation
- (void)animationDoneTimerFired:(NSTimer *)timer {
_animationDoneTimer = nil;
// Set the normal one to have the final image and alpha value.
// Set the image and update us before ordering out the animation window.
self.imageViewMain.image = self.imageViewForTransition.image;
self.imageViewMain.alphaValue = 1.0;
// This displays right now, and prevents flicker if the animation window orders out before our display happened.
[self.imageViewMain.window displayIfNeeded];
// Hide the animation window.
[self.windowForAnimation orderOut:nil];
}
- (void)ensureAnimationWindowCreated {
if (self.windowForAnimation == nil) {
NSRect contentRect = self.imageViewForTransition.frame;
contentRect.origin = NSZeroPoint;
self.imageViewForTransition.frame = contentRect;
_windowForAnimation = [[NSWindow alloc] initWithContentRect:contentRect styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:NO];
self.windowForAnimation.releasedWhenClosed = NO;
self.windowForAnimation.opaque = NO;
self.windowForAnimation.backgroundColor = [NSColor clearColor];
// For ease of use, we setup the imageViewForTransition in the nib and add it as a subview.
[self.windowForAnimation.contentView addSubview:self.imageViewForTransition];
}
}
- (NSRect)screenImageRectForRow:(NSInteger)row {
NSRect result = NSZeroRect;
// We always want to try to get a view back to do the animation from that rect.
ATTableCellView *cellView = [self.tableViewMain viewAtColumn:0 row:row makeIfNecessary:YES];
if (cellView) {
result = [cellView.imageView convertRect:cellView.imageView.bounds toView:nil];
NSRect convertedRect = [cellView.window convertRectToScreen:NSMakeRect(result.origin.x, result.origin.y, 0.0, 0.0)];
result.origin = NSMakePoint(convertedRect.origin.x, convertedRect.origin.y);
}
return result;
}
- (NSRect)finalScreenImageRect {
// We are animating to right over the image view's frame. Convert to the right screen coordinates and animate the window there.
NSRect finalImageFrame = [self.imageViewMain.superview convertRect:self.imageViewMain.frame toView:nil];
NSRect convertedRect = [self.window convertRectToScreen:NSMakeRect(finalImageFrame.origin.x, finalImageFrame.origin.y, 0.0, 0.0)];
finalImageFrame.origin = NSMakePoint(convertedRect.origin.x, convertedRect.origin.y);
return finalImageFrame;
}
- (void)stopExistingTimerIfNeeded {
// We want to stop any previous animations.
if (self.animationDoneTimer != nil) {
[self.animationDoneTimer invalidate];
_animationDoneTimer = nil;
}
}
- (void)animateImageFromRow:(NSInteger)row {
[self stopExistingTimerIfNeeded];
// We create a window to do the animation.
// The purpose of using a window is to allow an animation to happen from a non-layer backed view to over a layer-backed view.
// We easily could use a sibling view if everything was layer backed, or non-layer backed.
[self ensureAnimationWindowCreated];
// Grab our model object for this row
ATDesktopImageEntity *entity = [self imageEntityForRow:row];
// Set some initial state
NSRect startingWindowFrame = [self screenImageRectForRow:row];
[self.windowForAnimation setFrame:startingWindowFrame display:NO];
self.imageViewForTransition.image = entity.thumbnailImage;
self.imageViewMain.alphaValue = 1.0;
// Bring the window above our existing window.
[self.windowForAnimation orderFront:nil];
// We want to sync all the animations together. We use a grouping to do that.
[NSAnimationContext beginGrouping];
{
NSTimeInterval animationDuration = 0.4;
// Do a slow animation if the shift key is down
if (([NSEvent modifierFlags] & NSEventModifierFlagShift) != 0) {
animationDuration *= 4;
}
[NSAnimationContext currentContext].duration = animationDuration;
NSRect finalImageFrame = [self finalScreenImageRect];
[[self.windowForAnimation animator] setFrame:finalImageFrame display:YES];
// Alpha/opacity animations only work for layer-backed views.
[self.imageViewMain animator].alphaValue = 0.25;
// Also, animate the background color. This is done with the layer. See ATColorView.h/.m
[self.colorViewMain animator].backgroundColor = entity.fillColor;
// At the end of the animation we want to do some cleanup.
// We keep track of the timer so we can stop the operation if we need to.
_animationDoneTimer =
[NSTimer scheduledTimerWithTimeInterval:animationDuration
target:self
selector:@selector(animationDoneTimerFired:)
userInfo:nil
repeats:NO];
}
[NSAnimationContext endGrouping];
}
#pragma mark - NSSplitViewDelegate
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
return 200;
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
// Make sure the view on the right has at least 200 px wide
CGFloat splitViewWidth = splitView.bounds.size.width;
return splitViewWidth - 200;
}
#pragma mark - ATColorTableControllerDelegate
- (void)colorTableController:(ATColorTableController *)controller didChooseColor:(NSColor *)color named:(NSString *)colorName {
if (self.rowForEditingColor != -1) {
// Update our model.
ATDesktopImageEntity *entity = [self imageEntityForRow:self.rowForEditingColor];
entity.fillColorName = colorName;
entity.fillColor = color;
// Update the view; we could reload things, but this is faster.
ATTableCellView *cellView = [self.tableViewMain viewAtColumn:0 row:self.rowForEditingColor makeIfNecessary:NO];
cellView.colorView.backgroundColor = color;
cellView.subTitleTextField.stringValue = colorName;
} else {
// With no row we are just setting the background color.
self.colorViewMain.backgroundColor = color;
}
}
#pragma mark - Actions
- (IBAction)btnSetAsDesktopWallpaperClick:(id)sender {
NSInteger selectedRow = self.tableViewMain.selectedRow;
if (selectedRow != -1) {
ATDesktopEntity *entity = self.tableContents[selectedRow];
if ([entity isKindOfClass:[ATDesktopImageEntity class]]) {
ATDesktopImageEntity *desktopImageEntity = (ATDesktopImageEntity *)entity;
NSError *error;
NSURL *imageURL = desktopImageEntity.fileURL;
NSColor *fillColor = desktopImageEntity.fillColor;
NSDictionary *options =
@{NSWorkspaceDesktopImageFillColorKey: fillColor,
NSWorkspaceDesktopImageAllowClippingKey: @NO,
NSWorkspaceDesktopImageScalingKey: @(NSImageScaleProportionallyUpOrDown)};
BOOL result = [[NSWorkspace sharedWorkspace] setDesktopImageURL:imageURL
forScreen:[NSScreen screens].lastObject
options:options
error:&error];
if (!result) {
[NSApp presentError:error];
}
}
}
}
- (void)editColorOnRow:(NSInteger)row {
_rowForEditingColor = row;
ATTableCellView *cellView = [self.tableViewMain viewAtColumn:0 row:row makeIfNecessary:NO];
NSColor *color = cellView.colorView.backgroundColor;
[ATColorTableController sharedColorTableController].delegate = self;
[[ATColorTableController sharedColorTableController] editColor:color withPositioningView:cellView.colorView];
}
- (IBAction)cellColorViewClicked:(id)sender {
// Find out what row it was in and edit that color with the popup
NSInteger row = [self.tableViewMain rowForView:sender];
if (row != -1) {
[self editColorOnRow:row];
}
}
- (IBAction)textTitleChanged:(id)sender {
NSInteger row = [self.tableViewMain rowForView:sender];
if (row != -1) {
ATDesktopImageEntity *entity = [self imageEntityForRow:row];
entity.title = [sender stringValue];
}
}
- (IBAction)colorTitleChanged:(id)sender {
NSInteger row = [self.tableViewMain rowForView:sender];
if (row != -1) {
ATDesktopImageEntity *entity = [self imageEntityForRow:row];
entity.fillColorName = [sender stringValue];
}
}
- (void)selectRowStartingAtRow:(NSInteger)row {
if (self.tableViewMain.selectedRow == -1) {
if (row == -1) {
row = 0;
}
// Select the same or next row (if possible) but skip group rows
while (row < self.tableViewMain.numberOfRows) {
if (![self tableView:self.tableViewMain isGroupRow:row]) {
[self.tableViewMain selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
return;
}
row++;
}
row = self.tableViewMain.numberOfRows - 1;
while (row >= 0) {
if (![self tableView:self.tableViewMain isGroupRow:row]) {
[self.tableViewMain selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
return;
}
row--;
}
}
}
- (IBAction)btnRemoveRowClick:(id)sender {
NSInteger row = [self.tableViewMain rowForView:sender];
if (row != -1) {
[self.tableContents removeObjectAtIndex:row];
[self.tableViewMain removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationEffectFade];
[self selectRowStartingAtRow:row];
}
}
- (IBAction)btnRemoveAllSelectedRowsClick:(id)sender {
[self.tableContents removeObjectsAtIndexes:self.tableViewMain.selectedRowIndexes];
[self.tableViewMain removeRowsAtIndexes:self.tableViewMain.selectedRowIndexes withAnimation:NSTableViewAnimationEffectFade];
}
- (IBAction)btnInsertNewRow:(id)sender {
NSURL *url = [[NSWorkspace sharedWorkspace] desktopImageURLForScreen:[NSScreen mainScreen]];
ATDesktopImageEntity *entity = [[ATDesktopImageEntity alloc] initWithFileURL:url];
entity.fillColor = self.colorViewMain.backgroundColor;
entity.fillColorName = @"Untitled Color";
NSInteger index = self.tableViewMain.selectedRow;
if (index == -1) {
if (self.tableViewMain.numberOfRows == 0) {
index = 0;
} else {
index = 1;
}
}
[self.tableContents insertObject:entity atIndex:index];
[self.tableViewMain beginUpdates];
[self.tableViewMain insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:index] withAnimation:NSTableViewAnimationEffectFade];
[self.tableViewMain scrollRowToVisible:index];
[self.tableViewMain endUpdates];
}
- (IBAction)mainColorViewClicked:(id)sender {
_rowForEditingColor = -1;
NSColor *color = self.colorViewMain.backgroundColor;
[ATColorTableController sharedColorTableController].delegate = self;
[[ATColorTableController sharedColorTableController] editColor:color withPositioningView:self.colorViewMain];
}
// This is called when the the NSImageView changes.
- (IBAction)cellBtnAnimateImageClick:(id)sender {
NSInteger selectedRow = [self.tableViewMain rowForView:sender];
if (selectedRow != -1) {
[self.tableViewMain scrollRowToVisible:selectedRow];
// Only animate if the thumbnail image is loaded.
ATDesktopImageEntity *entity = self.tableContents[selectedRow];
if (entity.thumbnailImage != nil) {
[self animateImageFromRow:selectedRow];
}
} else {
self.imageViewMain.image = nil;
}
}
- (IBAction)chkbxHorizontalGridLineClicked:(id)sender {
if (((NSButton *)sender).state == 0) {
self.tableViewMain.gridStyleMask = NSTableViewGridNone;
} else {
self.tableViewMain.gridStyleMask = NSTableViewSolidHorizontalGridLineMask;
}
}
- (IBAction)chkbxUseSmallRowHeightClicked:(id)sender {
_useSmallRowHeight = ((NSButton *)sender).state == 1;
// Reload the height for all non group rows.
NSMutableIndexSet *indexesToNoteHeightChanges = [NSMutableIndexSet indexSet];
for (NSUInteger row = 0; row < self.tableContents.count; row++) {
if (![[self entityForRow:row] isKindOfClass:[ATDesktopFolderEntity class]]) {
[indexesToNoteHeightChanges addIndex:row];
}
}
// We also want to synchronize our own animations with the height change.
// We do this by creating our own animation grouping.
[NSAnimationContext beginGrouping];
[NSAnimationContext currentContext].duration = 1.5;
// Update all the current visible views animated in sync with the row heights.
[self.tableViewMain enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row) {
for (NSUInteger i = 0; i < self.tableViewMain.tableColumns.count; i++) {
NSView *view = [self.tableViewMain viewAtColumn:i row:row makeIfNecessary:NO];
if (view && [view isKindOfClass:[ATTableCellView class]]) {
[(ATTableCellView *)view layoutViewsForSmallSize:self.useSmallRowHeight animated:YES];
}
}
}];
[self.tableViewMain noteHeightOfRowsWithIndexesChanged:indexesToNoteHeightChanges];
[NSAnimationContext endGrouping];
}
- (IBAction)chkbxFloatGroupRowsClicked:(id)sender {
BOOL checked = ((NSButton *)sender).state == 1;
self.tableViewMain.floatsGroupRows = checked;
}
- (IBAction)btnBeginUpdatesClicked:(id)sender {
[self.tableViewMain beginUpdates];
}
- (IBAction)btnEndUpdatesClicked:(id)sender {
[self.tableViewMain endUpdates];
}
- (IBAction)btnMoveRowClick:(id)sender {
NSInteger fromRow = self.txtFldFromRow.integerValue;
NSInteger toRow = self.txtFldToRow.integerValue;
[self.tableViewMain beginUpdates];
[self.tableViewMain moveRowAtIndex:fromRow toIndex:toRow];
id object = self.tableContents[fromRow];
[self.tableContents removeObjectAtIndex:fromRow];
[self.tableContents insertObject:object atIndex:toRow];
[self.tableViewMain endUpdates];
}
- (IBAction)tblvwDoubleClick:(id)sender {
NSInteger row = self.tableViewMain.selectedRow;
if (row != -1) {
ATDesktopEntity *entity = [self entityForRow:row];
[[NSWorkspace sharedWorkspace] selectFile:entity.fileURL.path inFileViewerRootedAtPath:@""];
}
}
- (IBAction)btnManuallyBeginEditingClick:(id)sender {
NSInteger row = self.txtFldRowToEdit.integerValue;
[self.tableViewMain editColumn:0 row:row withEvent:nil select:YES];
}
- (NSIndexSet *)indexesToProcessForContextMenu {
NSIndexSet *selectedIndexes = self.tableViewMain.selectedRowIndexes;
// If the clicked row was in the selectedIndexes, then we process all selectedIndexes.
// Otherwise, we process just the clickedRow.
//
if (self.tableViewMain.clickedRow != -1 && ![selectedIndexes containsIndex:self.tableViewMain.clickedRow]) {
selectedIndexes = [NSIndexSet indexSetWithIndex:self.tableViewMain.clickedRow];
}
return selectedIndexes;
}
- (IBAction)mnuRevealInFinderSelected:(id)sender {
NSIndexSet *selectedIndexes = [self indexesToProcessForContextMenu];
[selectedIndexes enumerateIndexesUsingBlock:^(NSUInteger row, BOOL *stop) {
ATDesktopEntity *entity = [self entityForRow:row];
[[NSWorkspace sharedWorkspace] selectFile:entity.fileURL.path inFileViewerRootedAtPath:@""];
}];
}
- (IBAction)btnRevealInFinderSelected:(id)sender {
NSInteger row = [self.tableViewMain rowForView:sender];
ATDesktopEntity *entity = [self entityForRow:row];
[[NSWorkspace sharedWorkspace] selectFile:entity.fileURL.path inFileViewerRootedAtPath:@""];
}
- (IBAction)mnuRemoveRowSelected:(id)sender {
NSIndexSet *indexes = [self indexesToProcessForContextMenu];
[self.tableViewMain beginUpdates];
[self.tableContents removeObjectsAtIndexes:indexes];
[self.tableViewMain removeRowsAtIndexes:indexes withAnimation:NSTableViewAnimationEffectFade];
[self.tableViewMain endUpdates];
}
- (IBAction)btnChangeSelectionAnimated:(id)sender {
if (self.tableViewMain.selectedRow != -1) {
[[self.tableViewMain animator] selectRowIndexes:[NSIndexSet indexSet] byExtendingSelection:NO];
} else {
[[self.tableViewMain animator] selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
}
}
@end

View File

@ -0,0 +1,57 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A sample model object. A base abstract class (ATDesktopEntity) implements caching of a file URL. One concrete subclass implements the ability to have an array of children (ATDesktopFolderEntity). Another (ATDesktopImageEntity) represents an image suitable for the desktop wallpaper.
*/
@import Cocoa;
// KVO key path for thumbnail.
extern NSString *const ATEntityPropertyNamedThumbnailImage;
// Base abstract class that wraps a file system URL
@interface ATDesktopEntity : NSObject <NSPasteboardWriting, NSPasteboardReading>
- (instancetype)initWithFileURL:(NSURL *)fileURL NS_DESIGNATED_INITIALIZER;
@property (strong) NSString *title;
@property (strong) NSURL *fileURL;
+ (ATDesktopEntity *)entityForURL:(NSURL *)url;
@end
#pragma mark -
// Concrete subclass of ATDesktopEntity that loads children from a folder
@interface ATDesktopFolderEntity : ATDesktopEntity
@property(strong) NSMutableArray *children;
@end
#pragma mark -
// Concrete subclass of ATDesktopEntity that adds support for loading an image at the given URL and stores a fillColor property
@interface ATDesktopImageEntity : ATDesktopEntity
@property (strong) NSColor *fillColor;
@property (copy) NSString *fillColorName;
// Access to the image. This property can be observed to find out when it changes and is fully loaded.
@property (strong) NSImage *image;
@property (readonly, strong, nonatomic) NSImage *thumbnailImage;
// Asynchronously loads the image (if not already loaded). A KVO notification is sent out when the image is loaded.
- (void)loadImage;
// A nil image isn't loaded (or couldn't be loaded).
// An image that is in the process of loading has imageLoading set to YES.
@property (readonly) BOOL imageLoading;
@end

View File

@ -0,0 +1,307 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A sample model object. A base abstract class (ATDesktopEntity) implements caching of a file URL. One concrete subclass implements the ability to have an array of children (ATDesktopFolderEntity). Another (ATDesktopImageEntity) represents an image suitable for the desktop wallpaper.
*/
#import "ATDesktopEntity.h"
@import Quartz; // for IKImageBrowserNSURLRepresentationType
#define THUMBNAIL_HEIGHT 180.0
// For the purposes of a demo, we intentionally make things slower.
// Turning off the DEMO_MODE define will make things run at normal speed.
#define DEMO_MODE 0
NSString *const ATEntityPropertyNamedThumbnailImage = @"thumbnailImage";
#pragma mark -
@implementation ATDesktopEntity
@dynamic title;
+ (ATDesktopEntity *)entityForURL:(NSURL *)url {
// We create folder items or image items, and ignore everything else; all based on the UTI we get from the URL.
NSString *typeIdentifier;
if ([url getResourceValue:&typeIdentifier forKey:NSURLTypeIdentifierKey error:NULL]) {
NSArray *imageUTIs = [NSImage imageTypes];
if ([imageUTIs containsObject:typeIdentifier]) {
return [[ATDesktopImageEntity alloc] initWithFileURL:url];
} else if ([typeIdentifier isEqualToString:(NSString *)kUTTypeFolder]) {
return [[ATDesktopFolderEntity alloc] initWithFileURL:url];;
}
}
return nil;
}
- (instancetype)init {
NSAssert(NO, @"Invalid use of init; use initWithFileURL to create ATDesktopEntity");
return [self init];
}
- (instancetype)initWithFileURL:(NSURL *)fileURL {
self = [super init];
_fileURL = fileURL;
return self;
}
- (id)copyWithZone:(NSZone *)zone {
id result = [[[self class] alloc] initWithFileURL:self.fileURL];
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@ : %@", super.description, self.title];
}
- (NSString *)title {
NSString *result;
if ([self.fileURL getResourceValue:&result forKey:NSURLLocalizedNameKey error:NULL]) {
return result;
}
return nil;
}
#pragma mark - NSPasteboardWriting support
- (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard {
return [self.fileURL writableTypesForPasteboard:pasteboard];
}
- (id)pasteboardPropertyListForType:(NSString *)type {
return [self.fileURL pasteboardPropertyListForType:type];
}
- (NSPasteboardWritingOptions)writingOptionsForType:(NSString *)type pasteboard:(NSPasteboard *)pasteboard {
if ([self.fileURL respondsToSelector:@selector(writingOptionsForType:pasteboard:)]) {
return [self.fileURL writingOptionsForType:type pasteboard:pasteboard];
} else {
return 0;
}
}
#pragma mark - NSPasteboardReading support
+ (NSArray *)readableTypesForPasteboard:(NSPasteboard *)pasteboard {
// We allow creation from folder and image URLs only, but there is no way to specify just file URLs that contain images.
return @[(id)kUTTypeFolder, (id)kUTTypeFileURL];
}
+ (NSPasteboardReadingOptions)readingOptionsForType:(NSString *)type pasteboard:(NSPasteboard *)pasteboard {
return NSPasteboardReadingAsString;
}
#pragma mark - Image Support
- (NSString *)imageUID {
return [NSString stringWithFormat:@"%p", self];
}
- (NSString *)imageRepresentationType {
return IKImageBrowserNSURLRepresentationType;
}
- (id)imageRepresentation {
return self.fileURL;
}
- (NSUInteger)imageVersion {
return 0;
}
- (NSString *)imageTitle {
return self.title;
}
- (NSString *)imageSubtitle {
return nil;
}
- (BOOL)isSelectable {
return YES;
}
@end
#pragma mark -
@interface ATDesktopImageEntity () {
BOOL _imageLoading;
//NSString *_title;
NSImage *_image;
NSImage *_thumbnailImage;
NSColor *_fillColor;
NSString *_fillColorName;
}
// Private read/write access to the thumbnailImage.
@property (readwrite, strong, nonatomic) NSImage *thumbnailImage;
@property (readwrite) BOOL imageLoading;
@end
@implementation ATDesktopImageEntity
@synthesize fillColor = _fillColor;
@synthesize fillColorName = _fillColorName;
@synthesize imageLoading = _imageLoading;
@synthesize image = _image;
- (instancetype)initWithFileURL:(NSURL *)fileURL {
self = [super initWithFileURL:fileURL];
if (self != nil ) {
// Initialize our color to specific given color for testing purposes.
static NSUInteger lastColorIndex = 0;
NSColorList *colorList = [NSColorList colorListNamed:@"Crayons"];
NSArray *keys = colorList.allKeys;
if (lastColorIndex >= keys.count) {
lastColorIndex = 0;
}
_fillColorName = keys[lastColorIndex++];
_fillColor = [colorList colorWithKey:_fillColorName];
}
return self;
}
static NSImage *ATThumbnailImageFromImage(NSImage *image) {
NSSize imageSize = image.size;
CGFloat imageAspectRatio = imageSize.width / imageSize.height;
// Create a thumbnail image from this image (this part of the slow operation).
NSSize thumbnailSize = NSMakeSize(THUMBNAIL_HEIGHT * imageAspectRatio, THUMBNAIL_HEIGHT);
NSImage *thumbnailImage = [[NSImage alloc] initWithSize:thumbnailSize];
[thumbnailImage lockFocus];
[image drawInRect:NSMakeRect(0, 0, thumbnailSize.width, thumbnailSize.height) fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
[thumbnailImage unlockFocus];
#if DEMO_MODE
// We delay things with an explicit sleep to get things slower for the demo!
usleep(250000);
#endif
return thumbnailImage;
}
// Lazily load the thumbnail image when requested.
- (NSImage *)thumbnailImage {
if (self.image != nil && _thumbnailImage == nil) {
// Generate the thumbnail right now, synchronously.
_thumbnailImage = ATThumbnailImageFromImage(self.image);
} else if (self.image == nil && !self.imageLoading) {
// Load the image lazily.
[self loadImage];
}
return _thumbnailImage;
}
- (void)setThumbnailImage:(NSImage *)img {
if (img != _thumbnailImage) {
_thumbnailImage = img;
}
}
static NSOperationQueue *ATSharedOperationQueue() {
static NSOperationQueue *_ATSharedOperationQueue = nil;
if (_ATSharedOperationQueue == nil) {
_ATSharedOperationQueue = [[NSOperationQueue alloc] init];
// We limit the concurrency to see things easier for demo purposes.
// The default value NSOperationQueueDefaultMaxConcurrentOperationCount will yield better results,
// as it will create more threads, as appropriate for your processor.
//
_ATSharedOperationQueue.maxConcurrentOperationCount = 2;
}
return _ATSharedOperationQueue;
}
- (void)loadImage {
@synchronized (self) {
if (self.image == nil && !self.imageLoading) {
self.imageLoading = YES;
// We would have to keep track of the block with an NSBlockOperation,
// if we wanted to later support cancelling operations that have scrolled offscreen
// and are no longer needed. That will be left as an exercise to the user.
//
[ATSharedOperationQueue() addOperationWithBlock:^(void) {
NSImage *image = [[NSImage alloc] initWithContentsOfURL:self.fileURL];
if (image != nil) {
NSImage *thumbnailImage = ATThumbnailImageFromImage(image);
// We synchronize access to the image/imageLoading pair of variables.
@synchronized (self) {
self.imageLoading = NO;
self.image = image;
self.thumbnailImage = thumbnailImage;
}
} else {
@synchronized (self) {
self.image = [NSImage imageNamed:NSImageNameTrashFull];
}
}
}];
}
}
}
@end
#pragma mark -
@interface ATDesktopFolderEntity () {
NSMutableArray *_children;
}
@end
@implementation ATDesktopFolderEntity
@dynamic children;
- (NSMutableArray *)children {
NSMutableArray *result = nil;
// This property is declared as atomic. We use @synchronized to ensure that promise is kept.
@synchronized(self) {
// It would be nice if this was asycnhronous to avoid any stalls while we look at the file system.
// A mechanism similar to how the ATDesktopImageEntity loads images could be used here.
//
if (_children == nil && self.fileURL != nil) {
NSError *error = nil;
// Grab the URLs for the folder and wrap them in our entity objects
NSArray *urls = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:self.fileURL includingPropertiesForKeys:@[NSURLLocalizedNameKey] options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants error:&error];
NSMutableArray *newChildren = [[NSMutableArray alloc] initWithCapacity:urls.count];
for (NSURL *url in urls) {
// We create folder items or image items, and ignore everything else; all based on the UTI we get from the URL.
NSString *typeIdentifier;
if ([url getResourceValue:&typeIdentifier forKey:NSURLTypeIdentifierKey error:NULL]) {
ATDesktopEntity *entity = [ATDesktopEntity entityForURL:url];
if (entity) {
[newChildren addObject:entity];
}
}
}
_children = newChildren;
}
result = _children;
}
return result;
}
- (void)setChildren:(NSMutableArray *)value {
// This property is declared as atomic. We use @synchronized to ensure that promise is kept.
@synchronized(self) {
if (_children != value) {
_children = value;
}
}
}
@end

View File

@ -0,0 +1,13 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The main window controller for choosing different test windows to open.
*/
@import Cocoa;
@interface ATMainWindowController : NSWindowController
@end

View File

@ -0,0 +1,58 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The main window controller for choosing different test windows to open.
*/
#import "ATMainWindowController.h"
#import "ATComplexTableViewController.h"
#import "ATComplexOutlineController.h"
#import "ATBasicTableViewWindowController.h"
// Keys used for bindings
#define ATKeyClass @"class"
#define ATKeyName @"name"
#define ATKeyShortDescription @"shortDescription"
#define ATKeyImagePreview @"imagePreview"
@interface ATMainWindowController () <NSTableViewDelegate, NSTableViewDataSource>
@property (strong) NSMutableArray *tableContents;
@end
#pragma mark -
@implementation ATMainWindowController
- (void)awakeFromNib {
[super awakeFromNib];
// Note that "tableContents" is the backing of our NSArrayController which populates our NSTableView content.
_tableContents = [NSMutableArray array];
[self willChangeValueForKey:@"_tableContents"];
[self.tableContents addObject:@{ATKeyClass: [ATBasicTableViewWindowController class],
ATKeyName: @"Basic Table View",
ATKeyShortDescription: @"A Minimal View Based Implementation",
ATKeyImagePreview: [NSImage imageNamed: @"ATBasicTableViewWindowPreview"]}];
[self.tableContents addObject:@{ATKeyClass: [ATComplexTableViewController class],
ATKeyName: @"Complex Table View",
ATKeyShortDescription: @"A Complex Cell Example",
ATKeyImagePreview: [NSImage imageNamed: @"ATComplexTableViewControllerPreview"]}];
[self.tableContents addObject:@{ATKeyClass: [ATComplexOutlineController class],
ATKeyName: @"Complex Outline View",
ATKeyShortDescription: @"A Complex Bindings Example",
ATKeyImagePreview: [NSImage imageNamed: @"ATComplexOutlineControllerPreview"]}];
[self didChangeValueForKey:@"_tableContents"];
}
@end

View File

@ -0,0 +1,18 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A simple subclass of NSTableRowView that introduces an objectValue property.
*/
@import Cocoa;
@interface ATObjectTableRowView : NSTableRowView {
@private
id _objectValue;
}
@property(strong) id objectValue;
@end

View File

@ -0,0 +1,15 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A simple subclass of NSTableRowView that introduces an objectValue property.
*/
#import "ATObjectTableRowView.h"
@implementation ATObjectTableRowView
@synthesize objectValue = _objectValue;
@end

View File

@ -0,0 +1,13 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
ATSampleWindowRowView implementation. This class is used because the NIB has an ATSampleWindowRowView placed in it with a special key of NSTableViewRowViewKey. NSTableView first looks for a view with that key for the row view, if the delegate method tableView:rowViewForRow: is not used.
*/
@import Cocoa;
@interface ATSampleWindowRowView : NSTableRowView
@end

View File

@ -0,0 +1,57 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
ATSampleWindowRowView implementation. This class is used because the NIB has an ATSampleWindowRowView placed in it with a special key of NSTableViewRowViewKey. NSTableView first looks for a view with that key for the row view, if the delegate method tableView:rowViewForRow: is not used.
*/
#import "ATSampleWindowRowView.h"
@implementation ATSampleWindowRowView
- (void)drawSelectionInRect:(NSRect)dirtyRect {
NSColor *primaryColor = [[NSColor alternateSelectedControlColor] colorWithAlphaComponent:0.5];
NSColor *secondarySelectedControlColor = [[NSColor secondarySelectedControlColor] colorWithAlphaComponent:0.5];
// Implement our own custom alpha drawing.
switch (self.selectionHighlightStyle) {
case NSTableViewSelectionHighlightStyleRegular: {
if (self.selected) {
if (self.emphasized) {
[primaryColor set];
} else {
[secondarySelectedControlColor set];
}
NSRect bounds = self.bounds;
const NSRect *rects = NULL;
NSInteger count = 0;
[self getRectsBeingDrawn:&rects count:&count];
for (NSInteger i = 0; i < count; i++) {
NSRect rect = NSIntersectionRect(bounds, rects[i]);
NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver);
}
}
break;
}
default: {
// Do super's drawing.
[super drawSelectionInRect:dirtyRect];
break;
}
}
}
- (void)drawSeparatorInRect:(NSRect)dirtyRect {
// Draw the grid.
NSRect sepRect = self.bounds;
sepRect.origin.y = NSMaxY(sepRect) - 1;
sepRect.size.height = 1;
sepRect = NSIntersectionRect(sepRect, dirtyRect);
if (!NSIsEmptyRect(sepRect)) {
[[NSColor gridColor] set];
NSRectFill(sepRect);
}
}
@end

View File

@ -0,0 +1,21 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A basic subclass of NSTableCellView that adds some properties strictly for allowing access to the items in code.
*/
@import Cocoa;
@class ATColorView;
@interface ATTableCellView : NSTableCellView
@property (weak) IBOutlet NSTextField *subTitleTextField;
@property (weak) IBOutlet ATColorView *colorView;
@property (weak) IBOutlet NSProgressIndicator *progessIndicator;
- (void)layoutViewsForSmallSize:(BOOL)smallSize animated:(BOOL)animated;
@end

View File

@ -0,0 +1,64 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
A basic subclass of NSTableCellView that adds some properties strictly for allowing access to the items in code.
*/
#import "ATTableCellView.h"
#import "ATColorView.h"
@interface ATTableCellView ()
@property (assign) BOOL isSmallSize;
@property (weak) IBOutlet NSButton *removeButton;
@end
#pragma mark -
@implementation ATTableCellView
- (void)layoutViewsForSmallSize:(BOOL)smallSize animated:(BOOL)animated {
if (self.isSmallSize != smallSize) {
_isSmallSize = smallSize;
CGFloat targetAlpha = self.isSmallSize ? 0 : 1;
if (animated) {
self.removeButton.animator.alphaValue = targetAlpha;
self.colorView.animator.alphaValue = targetAlpha;
self.subTitleTextField.animator.alphaValue = targetAlpha;
} else {
self.removeButton.alphaValue = targetAlpha;
self.colorView.alphaValue = targetAlpha;
self.subTitleTextField.alphaValue = targetAlpha;
}
}
}
- (NSArray *)draggingImageComponents {
// Start with what is already there (this is an image and text component).
NSMutableArray *result = [super.draggingImageComponents mutableCopy];
// Snapshot the color view and add it in.
NSRect viewBounds = self.colorView.bounds;
NSBitmapImageRep *imageRep = [self.colorView bitmapImageRepForCachingDisplayInRect:viewBounds];
[self.colorView cacheDisplayInRect:viewBounds toBitmapImageRep:imageRep];
NSImage *draggedImage = [[NSImage alloc] initWithSize:imageRep.size];
[draggedImage addRepresentation:imageRep];
// Add in another component.
NSDraggingImageComponent *colorComponent = [NSDraggingImageComponent draggingImageComponentWithKey:@"Color"];
colorComponent.contents = draggedImage;
// Convert the frame to our coordinate system.
viewBounds = [self convertRect:viewBounds fromView:self.colorView];
colorComponent.frame = viewBounds;
[result addObject:colorComponent];
return result;
}
@end

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12113" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ATBasicTableViewWindowController">
<connections>
<outlet property="tableView" destination="6" id="Pgr-lO-TYJ"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Basic TableView Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" frameAutosaveName="BasicTable" animationBehavior="default" id="1">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1578"/>
<value key="minSize" type="size" width="300" height="197"/>
<view key="contentView" id="2">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="3">
<rect key="frame" x="-1" y="-1" width="482" height="272"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" id="jNB-O0-NhV">
<rect key="frame" x="1" y="0.0" width="480" height="271"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" headerView="7" viewBased="YES" id="6">
<rect key="frame" x="0.0" y="0.0" width="480" height="248"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="MainCell" width="383" minWidth="40" maxWidth="1000" id="8">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Name/Image">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="11">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="MainCell" id="15">
<rect key="frame" x="1" y="1" width="383" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView id="16">
<rect key="frame" x="4" y="0.0" width="17" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="19"/>
</imageView>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="17">
<rect key="frame" x="26" y="0.0" width="356" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="18">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="imageView" destination="16" id="20"/>
<outlet property="textField" destination="17" id="21"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="SizeCell" width="91" minWidth="40" maxWidth="1000" id="9">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Size">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="10">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="22">
<rect key="frame" x="387" y="1" width="91" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" identifier="SizeCell" title="Label" id="23">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="12"/>
<outlet property="delegate" destination="-2" id="13"/>
</connections>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="5">
<rect key="frame" x="1" y="256" width="465" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="4">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="7">
<rect key="frame" x="0.0" y="0.0" width="480" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
</subviews>
</view>
</window>
</objects>
<resources>
<image name="NSApplicationIcon" width="128" height="128"/>
</resources>
</document>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12113" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ATColorTableController">
<connections>
<outlet property="tableColorList" destination="2" id="hSU-VD-vqn"/>
<outlet property="view" destination="11" id="12"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<customView id="11">
<rect key="frame" x="0.0" y="0.0" width="260" height="417"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="27" horizontalPageScroll="10" verticalLineScroll="27" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="1">
<rect key="frame" x="5" y="5" width="250" height="407"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<clipView key="contentView" id="zg3-aK-Skz">
<rect key="frame" x="1" y="1" width="248" height="405"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowHeight="25" viewBased="YES" id="2">
<rect key="frame" x="0.0" y="0.0" width="248" height="405"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn width="245" minWidth="40" maxWidth="1000" id="5">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="6">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="13" customClass="ATTableCellView">
<rect key="frame" x="1" y="1" width="245" height="34"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="15">
<rect key="frame" x="30" y="9" width="216" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" title="Sub Text" id="16">
<font key="font" metaFont="system"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<customView id="14" customClass="ATColorView">
<rect key="frame" x="1" y="5" width="25" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</customView>
</subviews>
<connections>
<accessibilityConnection property="title" destination="15" id="17"/>
<outlet property="colorView" destination="14" id="18"/>
<outlet property="subTitleTextField" destination="15" id="19"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="7"/>
<outlet property="delegate" destination="-2" id="8"/>
</connections>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="3">
<rect key="frame" x="-100" y="-100" width="224" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="4">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
</customView>
</objects>
</document>

View File

@ -0,0 +1,314 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ATComplexOutlineController">
<connections>
<outlet property="outlineView" destination="6" id="lK8-Ej-1ul"/>
<outlet property="pathCtrlRootDirectory" destination="20" id="hUY-Yx-wj2"/>
<outlet property="sharedDateFormatter" destination="48" id="c7M-Q3-CiU"/>
<outlet property="window" destination="1" id="12"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Complex OutlineView" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" frameAutosaveName="OutlineTable" animationBehavior="default" id="1">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="100" width="790" height="695"/>
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="778"/>
<value key="minSize" type="size" width="690" height="248"/>
<view key="contentView" id="2">
<rect key="frame" x="0.0" y="0.0" width="790" height="695"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="3">
<rect key="frame" x="-1" y="73" width="792" height="623"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" id="o5l-b4-mqq">
<rect key="frame" x="1" y="0.0" width="790" height="622"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" autosaveColumns="NO" headerView="7" viewBased="YES" indentationPerLevel="16" outlineTableColumn="8" id="6">
<rect key="frame" x="0.0" y="0.0" width="790" height="599"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="MainCell" width="360" minWidth="16" maxWidth="1000" id="8">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Desktop Image">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="11">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="MainCell" id="109" userLabel="MainCell" customClass="ATTableCellView">
<rect key="frame" x="1" y="1" width="360" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView tag="1" id="113">
<rect key="frame" x="3" y="0.0" width="28" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="114"/>
<connections>
<binding destination="109" name="value" keyPath="objectValue.thumbnailImage" id="121"/>
</connections>
</imageView>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="112">
<rect key="frame" x="32" y="7" width="245" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" title="Text Field (uses bindings)" id="115">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="109" name="value" keyPath="objectValue.title" id="120"/>
</connections>
</textField>
<button verticalHuggingPriority="750" id="111">
<rect key="frame" x="306" y="5" width="49" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" title="Reveal" bezelStyle="roundedRect" alignment="center" controlSize="small" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="116">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="smallSystem"/>
</buttonCell>
<connections>
<action selector="btnInCellClicked:" target="-2" id="123"/>
</connections>
</button>
<button verticalHuggingPriority="750" id="110">
<rect key="frame" x="282" y="5" width="21" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" title="X" bezelStyle="roundedRect" alignment="center" controlSize="small" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="117">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="smallSystem"/>
</buttonCell>
<connections>
<action selector="btnDeleteRowClicked:" target="-2" id="122"/>
</connections>
</button>
</subviews>
<connections>
<outlet property="imageView" destination="113" id="118"/>
<outlet property="textField" destination="112" id="119"/>
</connections>
</tableCellView>
<tableCellView identifier="GroupCell" id="101">
<rect key="frame" x="1" y="33" width="360" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView tag="1" id="102">
<rect key="frame" x="0.0" y="0.0" width="28" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSFolder" id="105"/>
</imageView>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="103">
<rect key="frame" x="27" y="2" width="272" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" title="Main Group Title" id="104">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="101" name="value" keyPath="objectValue.title" id="108"/>
</connections>
</textField>
</subviews>
<connections>
<outlet property="imageView" destination="102" id="106"/>
<outlet property="textField" destination="103" id="107"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="DateCell" width="204.94921875" minWidth="40" maxWidth="1000" id="9">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Date Modified">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="10">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<textField identifier="DateCell" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="133" userLabel="DateTextCell">
<rect key="frame" x="364" y="1" width="205" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Date Label (uses bindings)" id="134">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="ColorCell" width="216" minWidth="10" maxWidth="3.4028234663852886e+38" id="15">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Color">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="16">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="ColorCell" id="124" userLabel="ColorCell" customClass="ATTableCellView">
<rect key="frame" x="572" y="1" width="216" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="126">
<rect key="frame" x="19" y="0.0" width="189" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" title="Color Title (uses bindings)" id="127">
<font key="font" metaFont="system"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="124" name="textColor" keyPath="objectValue.fillColor" id="128"/>
<binding destination="124" name="value" keyPath="objectValue.fillColorName" id="132"/>
</connections>
</textField>
<customView id="125" customClass="ATColorView">
<rect key="frame" x="0.0" y="1" width="15" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</customView>
</subviews>
<connections>
<accessibilityConnection property="title" destination="126" id="131"/>
<outlet property="colorView" destination="125" id="130"/>
<outlet property="subTitleTextField" destination="126" id="129"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="13"/>
<outlet property="delegate" destination="-2" id="14"/>
</connections>
</outlineView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="0.65048545598983765" horizontal="YES" id="5">
<rect key="frame" x="1" y="540" width="781" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="4">
<rect key="frame" x="767" y="17" width="15" height="523"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="7">
<rect key="frame" x="0.0" y="0.0" width="790" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="18">
<rect key="frame" x="17" y="48" width="99" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Root Directory:" id="19">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="78">
<rect key="frame" x="17" y="24" width="119" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Background color:" id="79">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<pathControl verticalHuggingPriority="750" allowsExpansionToolTips="YES" id="20">
<rect key="frame" x="118" y="44" width="146" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<pathCell key="cell" controlSize="small" selectable="YES" editable="YES" alignment="left" placeholderString="Desktop Pictures" pathStyle="popUp" id="21">
<font key="font" metaFont="smallSystem"/>
</pathCell>
<connections>
<action selector="pathCtrlValueChanged:" target="-2" id="22"/>
</connections>
</pathControl>
<button verticalHuggingPriority="750" id="60">
<rect key="frame" x="269" y="45" width="154" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" title="Delete selected items" bezelStyle="roundedRect" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="61">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnDeletedSelectedRowsClicked:" target="-2" id="62"/>
</connections>
</button>
<button verticalHuggingPriority="750" id="63">
<rect key="frame" x="532" y="45" width="139" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" title="Demo Batched Moves" bezelStyle="roundedRect" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="64">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnDemoBatchedMoves:" target="-2" id="70"/>
</connections>
</button>
<button verticalHuggingPriority="750" id="66">
<rect key="frame" x="431" y="45" width="93" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" title="Demo Move" bezelStyle="roundedRect" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="67">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnDemoMove:" target="-2" id="69"/>
</connections>
</button>
<button id="71">
<rect key="frame" x="267" y="23" width="133" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="check" title="Float Group Rows" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="72">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="chkbxFloatGroupRowsClicked:" target="-2" id="73"/>
</connections>
</button>
<colorWell id="80">
<rect key="frame" x="141" y="20" width="36" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="color" name="controlColor" catalog="System" colorSpace="catalog"/>
<connections>
<action selector="clrWellChanged:" target="-2" id="81"/>
</connections>
</colorWell>
</subviews>
</view>
</window>
<dateFormatter dateStyle="medium" id="48" userLabel="SharedDateFormatter"/>
</objects>
<resources>
<image name="NSApplicationIcon" width="128" height="128"/>
<image name="NSFolder" width="32" height="32"/>
</resources>
</document>

View File

@ -0,0 +1,429 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12113" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ATComplexTableViewController">
<connections>
<outlet property="colorViewMain" destination="23" id="1yE-oc-Vmy"/>
<outlet property="imageViewForTransition" destination="3" id="o7M-rb-axS"/>
<outlet property="imageViewMain" destination="20" id="Ksg-qw-foA"/>
<outlet property="mainSplitView" destination="7" id="Mlt-EQ-65C"/>
<outlet property="tableViewMain" destination="39" id="X5o-ze-WI5"/>
<outlet property="txtFldFromRow" destination="13" id="KG2-6c-B6D"/>
<outlet property="txtFldRowToEdit" destination="65" id="1SF-Sd-cSb"/>
<outlet property="txtFldToRow" destination="12" id="mRT-88-z0K"/>
<outlet property="window" destination="5" id="49"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Complex Cell TableView" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" frameAutosaveName="ComplexTable" animationBehavior="default" id="5">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="213" width="607" height="540"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1578"/>
<value key="minSize" type="size" width="607" height="540"/>
<view key="contentView" id="6">
<rect key="frame" x="0.0" y="0.0" width="607" height="540"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<splitView autosaveName="SplitView" dividerStyle="thin" vertical="YES" id="7" userLabel="SplitView">
<rect key="frame" x="0.0" y="0.0" width="876" height="540"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="8">
<rect key="frame" x="0.0" y="0.0" width="247" height="540"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" id="H36-LU-kgE">
<rect key="frame" x="1" y="1" width="245" height="538"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" autosaveColumns="NO" viewBased="YES" id="39">
<rect key="frame" x="0.0" y="0.0" width="245" height="538"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="MainCell" width="242" minWidth="40" maxWidth="1000" id="42">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="43">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="MainCell" id="102" userLabel="MainCell" customClass="ATTableCellView">
<rect key="frame" x="1" y="1" width="242" height="75"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView tag="1" id="107">
<rect key="frame" x="8" y="7" width="85" height="62"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<imageCell key="cell" selectable="YES" editable="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="NSApplicationIcon" id="111"/>
<connections>
<action selector="cellBtnAnimateImageClick:" target="-2" id="122"/>
</connections>
</imageView>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="109">
<rect key="frame" x="98" y="43" width="116" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" title="Sample Text!" id="110">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<action selector="textTitleChanged:" target="-2" id="125"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="103">
<rect key="frame" x="131" y="19" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" title="Sub Text" id="114">
<font key="font" metaFont="system"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<action selector="colorTitleChanged:" target="-2" id="124"/>
</connections>
</textField>
<customView id="108" customClass="ATColorView">
<rect key="frame" x="101" y="15" width="25" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<connections>
<action selector="cellColorViewClicked:" target="-2" id="123"/>
</connections>
</customView>
<progressIndicator hidden="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" bezeled="NO" indeterminate="YES" style="spinning" id="106">
<rect key="frame" x="34" y="22" width="32" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</progressIndicator>
<button verticalHuggingPriority="750" misplaced="YES" imageHugsTitle="YES" id="104">
<rect key="frame" x="215" y="14" width="18" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" bezelStyle="roundedRect" image="NSRemoveTemplate" imagePosition="only" alignment="center" borderStyle="border" imageScaling="axesIndependently" inset="2" id="113">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnRemoveRowClick:" target="-2" id="121"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="105">
<rect key="frame" x="215" y="39" width="18" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" bezelStyle="roundedRect" image="NSRevealFreestandingTemplate" imagePosition="only" alignment="center" borderStyle="border" imageScaling="proportionallyUpOrDown" inset="2" id="112">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnRevealInFinderSelected:" target="-2" id="128"/>
</connections>
</button>
</subviews>
<connections>
<outlet property="colorView" destination="108" id="120"/>
<outlet property="imageView" destination="107" id="117"/>
<outlet property="progessIndicator" destination="106" id="116"/>
<outlet property="removeButton" destination="104" id="115"/>
<outlet property="subTitleTextField" destination="103" id="118"/>
<outlet property="textField" destination="109" id="119"/>
</connections>
</tableCellView>
<textField identifier="TextCell" verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="126">
<rect key="frame" x="1" y="78" width="242" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" alignment="center" title="Sample Centered Text!" id="127">
<font key="font" metaFont="systemBold"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="59"/>
<outlet property="delegate" destination="-2" id="60"/>
<outlet property="menu" destination="72" id="76"/>
</connections>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="40">
<rect key="frame" x="1" y="523" width="245" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="41">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<customView id="9">
<rect key="frame" x="248" y="0.0" width="628" height="540"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView wantsLayer="YES" id="20">
<rect key="frame" x="20" y="281" width="326" height="244"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<imageCell key="cell" selectable="YES" editable="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="NSUser" id="26"/>
</imageView>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="21">
<rect key="frame" x="119" y="254" width="138" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Set as Wallpaper" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="25">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnSetAsDesktopWallpaperClick:" target="-2" id="55"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="19">
<rect key="frame" x="10" y="167" width="138" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Insert as new row" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="27">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnInsertNewRow:" target="-2" id="52"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="16">
<rect key="frame" x="10" y="201" width="138" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Begin Updates" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="30">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnBeginUpdatesClicked:" target="-2" id="50"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="62">
<rect key="frame" x="131" y="97" width="154" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Manually Begin Editing" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="63">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnManuallyBeginEditingClick:" target="-2" id="70"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="93">
<rect key="frame" x="35" y="12" width="154" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Show Selection Fade" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="94">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnChangeSelectionAnimated:" target="-2" id="101"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="15">
<rect key="frame" x="156" y="201" width="138" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="End Updates" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="31">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnEndUpdatesClicked:" target="-2" id="51"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="14">
<rect key="frame" x="196" y="135" width="72" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Apply" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="32">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnMoveRowClick:" target="-2" id="53"/>
</connections>
</button>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="18">
<rect key="frame" x="156" y="167" width="138" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="Delete selected rows" bezelStyle="roundedRect" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="28">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<action selector="btnRemoveAllSelectedRowsClick:" target="-2" id="54"/>
</connections>
</button>
<customView wantsLayer="YES" id="23" customClass="ATColorView">
<rect key="frame" x="87" y="257" width="17" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<connections>
<action selector="mainColorViewClicked:" target="-2" id="58"/>
</connections>
</customView>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="22">
<rect key="frame" x="17" y="257" width="65" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Fill Color:" id="24">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="82">
<rect key="frame" x="45" y="224" width="211" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Batch changes inside an update block:" id="83">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button imageHugsTitle="YES" id="17">
<rect key="frame" x="35" y="57" width="156" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Horizontal Grid Lines" bezelStyle="regularSquare" imagePosition="leading" alignment="left" inset="2" id="29">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="chkbxHorizontalGridLineClicked:" target="-2" id="129"/>
</connections>
</button>
<button imageHugsTitle="YES" id="88">
<rect key="frame" x="35" y="37" width="156" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Float Group Rows" bezelStyle="regularSquare" imagePosition="leading" alignment="left" state="on" inset="2" id="89">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="chkbxFloatGroupRowsClicked:" target="-2" id="92"/>
</connections>
</button>
<button imageHugsTitle="YES" id="84">
<rect key="frame" x="34" y="77" width="159" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Use Small Row Height" bezelStyle="regularSquare" imagePosition="leading" alignment="left" inset="2" id="85">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="chkbxUseSmallRowHeightClicked:" target="-2" id="87"/>
</connections>
</button>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="13">
<rect key="frame" x="95" y="134" width="29" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="0" drawsBackground="YES" id="33">
<numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" maximumFractionDigits="3" id="34"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="12">
<rect key="frame" x="155" y="134" width="29" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="5" drawsBackground="YES" id="35">
<numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" maximumFractionDigits="3" id="36"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="65">
<rect key="frame" x="94" y="97" width="29" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="1" drawsBackground="YES" id="66">
<numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" maximumFractionDigits="3" id="67"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="11">
<rect key="frame" x="17" y="138" width="76" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Move from:" id="37">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="68">
<rect key="frame" x="33" y="101" width="63" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="For row:" id="69">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" id="10">
<rect key="frame" x="129" y="137" width="21" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="to:" id="38">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</customView>
</subviews>
<holdingPriorities>
<real value="250"/>
<real value="250"/>
</holdingPriorities>
<connections>
<outlet property="delegate" destination="-2" id="2DE-68-naZ"/>
</connections>
</splitView>
</subviews>
</view>
<point key="canvasLocation" x="235" y="97"/>
</window>
<imageView id="3" userLabel="imageViewForTransition">
<rect key="frame" x="0.0" y="0.0" width="294" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="NSUser" id="4"/>
<point key="canvasLocation" x="250" y="565"/>
</imageView>
<menu id="72" userLabel="cntxMnuTableView">
<items>
<menuItem title="Reveal in Finder" id="73">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="mnuRevealInFinderSelected:" target="-2" id="80"/>
</connections>
</menuItem>
<menuItem title="Delete Row" id="77">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="mnuRemoveRowSelected:" target="-2" id="81"/>
</connections>
</menuItem>
</items>
</menu>
</objects>
<resources>
<image name="NSApplicationIcon" width="128" height="128"/>
<image name="NSRemoveTemplate" width="11" height="11"/>
<image name="NSRevealFreestandingTemplate" width="14" height="14"/>
<image name="NSUser" width="32" height="32"/>
</resources>
</document>

View File

@ -0,0 +1,757 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12113" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="677" id="678"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<menu title="AMainMenu" systemMenu="main" id="29">
<items>
<menuItem title="TableViewPlayground" id="56">
<menu key="submenu" title="TableViewPlayground" systemMenu="apple" id="57">
<items>
<menuItem title="About TableViewPlayground" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="236">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Preferences…" keyEquivalent="," id="129"/>
<menuItem isSeparatorItem="YES" id="143">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Services" id="131">
<menu key="submenu" title="Services" systemMenu="services" id="130"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="144">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Hide TableViewPlayground" keyEquivalent="h" id="134">
<connections>
<action selector="hide:" target="-1" id="367"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="145">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="368"/>
</connections>
</menuItem>
<menuItem title="Show All" id="150">
<connections>
<action selector="unhideAllApplications:" target="-1" id="370"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="149">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Quit TableViewPlayground" keyEquivalent="q" id="136">
<connections>
<action selector="terminate:" target="-3" id="449"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="83">
<menu key="submenu" title="File" id="81">
<items>
<menuItem title="Close" keyEquivalent="w" id="73">
<connections>
<action selector="performClose:" target="-1" id="193"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="217">
<menu key="submenu" title="Edit" id="205">
<items>
<menuItem title="Undo" keyEquivalent="z" id="207">
<connections>
<action selector="undo:" target="-1" id="223"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="215">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="redo:" target="-1" id="231"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="206">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Cut" keyEquivalent="x" id="199">
<connections>
<action selector="cut:" target="-1" id="228"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="197">
<connections>
<action selector="copy:" target="-1" id="224"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="203">
<connections>
<action selector="paste:" target="-1" id="226"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="485">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="486"/>
</connections>
</menuItem>
<menuItem title="Delete" id="202">
<connections>
<action selector="delete:" target="-1" id="235"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="198">
<connections>
<action selector="selectAll:" target="-1" id="232"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="214">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Find" id="218">
<menu key="submenu" title="Find" id="220">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
<connections>
<action selector="performFindPanelAction:" target="-1" id="241"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="208">
<connections>
<action selector="performFindPanelAction:" target="-1" id="487"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="488"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221">
<connections>
<action selector="performFindPanelAction:" target="-1" id="489"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="210">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="216">
<menu key="submenu" title="Spelling and Grammar" id="200">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="204">
<connections>
<action selector="showGuessPanel:" target="-1" id="230"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="201">
<connections>
<action selector="checkSpelling:" target="-1" id="225"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="453"/>
<menuItem title="Check Spelling While Typing" id="219">
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="346">
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="347"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="454">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="456"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="348">
<menu key="submenu" title="Substitutions" id="349">
<items>
<menuItem title="Show Substitutions" id="457">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="458"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="459"/>
<menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="460">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="461"/>
</connections>
</menuItem>
<menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="462">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="463"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="450">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="451">
<items>
<menuItem title="Make Upper Case" id="452">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="464"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="465">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="468"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="466">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="467"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="211">
<menu key="submenu" title="Speech" id="212">
<items>
<menuItem title="Start Speaking" id="196">
<connections>
<action selector="startSpeaking:" target="-1" id="233"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="195">
<connections>
<action selector="stopSpeaking:" target="-1" id="227"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="375">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="376">
<items>
<menuItem title="Font" id="377">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="388">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="389">
<connections>
<action selector="orderFrontFontPanel:" target="420" id="424"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="390">
<connections>
<action selector="addFontTrait:" target="420" id="421"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="391">
<connections>
<action selector="addFontTrait:" target="420" id="422"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="392">
<connections>
<action selector="underline:" target="-1" id="432"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="393"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="394">
<connections>
<action selector="modifyFont:" target="420" id="425"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="395">
<connections>
<action selector="modifyFont:" target="420" id="423"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="396"/>
<menuItem title="Kern" id="397">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="415">
<items>
<menuItem title="Use Default" id="416">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="438"/>
</connections>
</menuItem>
<menuItem title="Use None" id="417">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="441"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="418">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="431"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="419">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="435"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligature" id="398">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligature" id="411">
<items>
<menuItem title="Use Default" id="412">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="439"/>
</connections>
</menuItem>
<menuItem title="Use None" id="413">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="440"/>
</connections>
</menuItem>
<menuItem title="Use All" id="414">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="434"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="399">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="405">
<items>
<menuItem title="Use Default" id="406">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="437"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="407">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="430"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="408">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="429"/>
</connections>
</menuItem>
<menuItem title="Raise" id="409">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="426"/>
</connections>
</menuItem>
<menuItem title="Lower" id="410">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="427"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="400"/>
<menuItem title="Show Colors" keyEquivalent="C" id="401">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="433"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="402"/>
<menuItem title="Copy Style" keyEquivalent="c" id="403">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="428"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="404">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="436"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="496">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="497">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="498">
<connections>
<action selector="alignLeft:" target="-1" id="524"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="499">
<connections>
<action selector="alignCenter:" target="-1" id="518"/>
</connections>
</menuItem>
<menuItem title="Justify" id="500">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="523"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="501">
<connections>
<action selector="alignRight:" target="-1" id="521"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="502"/>
<menuItem title="Writing Direction" id="503">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="508">
<items>
<menuItem title="Paragraph" enabled="NO" id="509">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="510">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="525"/>
</connections>
</menuItem>
<menuItem id="511">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="526"/>
</connections>
</menuItem>
<menuItem id="512">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="527"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="513"/>
<menuItem title="Selection" enabled="NO" id="514">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="515">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="528"/>
</connections>
</menuItem>
<menuItem id="516">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="529"/>
</connections>
</menuItem>
<menuItem id="517">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="530"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="504"/>
<menuItem title="Show Ruler" id="505">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="520"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="506">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="522"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="507">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="519"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="295">
<menu key="submenu" title="View" id="296">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="297">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="366"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="298">
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="19">
<menu key="submenu" title="Window" systemMenu="window" id="24">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="23">
<connections>
<action selector="performMiniaturize:" target="-1" id="37"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="239">
<connections>
<action selector="performZoom:" target="-1" id="240"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="92">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Bring All to Front" id="5">
<connections>
<action selector="arrangeInFront:" target="-1" id="39"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="490">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="491">
<items>
<menuItem title="TableViewPlayground Help" keyEquivalent="?" id="492">
<connections>
<action selector="showHelp:" target="-1" id="493"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<customObject id="420" customClass="NSFontManager"/>
<customObject id="677" userLabel="ATApplicationController" customClass="ATApplicationController">
<connections>
<outlet property="mainWindowController" destination="hUo-Gv-STY" id="DpO-04-yBn"/>
</connections>
</customObject>
<window title="TableViewPlayground" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="690" userLabel="SampleWindowsPanel" customClass="NSPanel">
<windowStyleMask key="styleMask" titled="YES" miniaturizable="YES" resizable="YES" utility="YES" HUD="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="890" y="730" width="358" height="314"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1578"/>
<value key="minSize" type="size" width="358" height="314"/>
<view key="contentView" misplaced="YES" id="691">
<rect key="frame" x="0.0" y="0.0" width="358" height="314"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField verticalHuggingPriority="750" misplaced="YES" allowsCharacterPickerTouchBarItem="NO" id="694">
<rect key="frame" x="18" y="287" width="328" height="14"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Available Sample Windows" id="695">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView misplaced="YES" autohidesScrollers="YES" horizontalLineScroll="86" horizontalPageScroll="10" verticalLineScroll="86" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="700">
<rect key="frame" x="20" y="20" width="318" height="259"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="6Dt-i2-8Um">
<rect key="frame" x="1" y="1" width="316" height="257"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowHeight="84" viewBased="YES" id="703">
<rect key="frame" x="0.0" y="0.0" width="316" height="257"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" red="0.12669566269999999" green="0.32722973820000001" blue="0.55304801459999997" alpha="0.28999999170000001" colorSpace="calibratedRGB"/>
<tableViewGridLines key="gridStyleMask" horizontal="YES"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="SampleWindowCell" width="313" minWidth="40" maxWidth="1000" id="705">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="708">
<font key="font" metaFont="system"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<customView identifier="NSTableViewRowViewKey" id="760" customClass="ATSampleWindowRowView">
<rect key="frame" x="1" y="1" width="313" height="83"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</customView>
<tableCellView identifier="SampleWindowCell" id="725">
<rect key="frame" x="1" y="86" width="313" height="84"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView tag="1" id="732">
<rect key="frame" x="4" y="0.0" width="63" height="84"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="739"/>
<connections>
<binding destination="725" name="value" keyPath="objectValue.imagePreview" id="759"/>
</connections>
</imageView>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="733">
<rect key="frame" x="72" y="57" width="281" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" title="Main title " id="738">
<font key="font" metaFont="systemBold"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<accessibilityConnection property="title" destination="725" id="744"/>
<binding destination="725" name="value" keyPath="objectValue.name" id="740"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" tag="1" allowsCharacterPickerTouchBarItem="NO" id="734">
<rect key="frame" x="72" y="35" width="281" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" title="Short description" id="737">
<font key="font" metaFont="system"/>
<color key="textColor" red="0.68627450980000004" green="0.68627450980000004" blue="0.68627450980000004" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="725" name="value" keyPath="objectValue.shortDescription" id="741"/>
</connections>
</textField>
<button verticalHuggingPriority="750" imageHugsTitle="YES" id="735">
<rect key="frame" x="73" y="8" width="123" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundRect" title="Open New Window" bezelStyle="roundedRect" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="736">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<binding destination="725" name="argument" keyPath="objectValue.class" id="3F6-fK-SMr">
<dictionary key="options">
<string key="NSSelectorName">newWindowWithControllerClass:</string>
</dictionary>
</binding>
<binding destination="677" name="target" keyPath="self" previousBinding="3F6-fK-SMr" id="trG-1G-RuT">
<dictionary key="options">
<string key="NSSelectorName">newWindowWithControllerClass:</string>
</dictionary>
</binding>
</connections>
</button>
</subviews>
<connections>
<accessibilityConnection property="title" destination="733" id="745"/>
<outlet property="imageView" destination="732" id="742"/>
<outlet property="textField" destination="733" id="743"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<binding destination="719" name="content" keyPath="arrangedObjects" id="721"/>
<outlet property="delegate" destination="677" id="724"/>
</connections>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="702">
<rect key="frame" x="1" y="242" width="247" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="701">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
</view>
<point key="canvasLocation" x="130" y="431"/>
</window>
<customObject id="hUo-Gv-STY" userLabel="ATMainWindowController" customClass="ATMainWindowController">
<connections>
<outlet property="window" destination="690" id="oLZ-cc-NTR"/>
</connections>
</customObject>
<arrayController objectClassName="NSDictionary" editable="NO" id="719">
<declaredKeys>
<string>name</string>
</declaredKeys>
<connections>
<binding destination="hUo-Gv-STY" name="contentArray" keyPath="_tableContents" id="GJw-XI-GZP"/>
</connections>
</arrayController>
</objects>
<resources>
<image name="NSApplicationIcon" width="128" height="128"/>
</resources>
</document>

View File

@ -0,0 +1,4 @@
/* Localized versions of Info.plist keys */
CFBundleName = "TableViewPlayground";
NSHumanReadableCopyright = "Copyright © 2011-2017 Apple Inc.\nAll rights reserved.";

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ATBasicTableViewWindowPreview.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ATComplexOutlineControllerPreview.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ATComplexTableViewControllerPreview.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -0,0 +1,14 @@
/*
Copyright (C) 2017 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Main source code file for the project.
*/
@import Cocoa;
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}