NEW: CPViewController -viewWill/DidAppear & -viewWill/DidDisappear

When a view belonging to a CPViewController is hidden, unhidden, added
or removed, its viewController receives the appropriate message.

Added AppKit/CPViewControllerTest.
This commit is contained in:
cacaodev
2016-05-23 16:06:04 +02:00
parent e58420b031
commit b587a19a0f
7 changed files with 208 additions and 9 deletions
+36 -3
View File
@@ -112,6 +112,11 @@ CPViewHeightSizable = 16;
*/
CPViewMaxYMargin = 32;
_CPViewWillAppearNotification = @"CPViewWillAppearNotification";
_CPViewDidAppearNotification = @"CPViewDidAppearNotification";
_CPViewWillDisappearNotification = @"CPViewWillDisappearNotification";
_CPViewDidDisappearNotification = @"CPViewDidDisappearNotification";
CPViewBoundsDidChangeNotification = @"CPViewBoundsDidChangeNotification";
CPViewFrameDidChangeNotification = @"CPViewFrameDidChangeNotification";
@@ -404,7 +409,6 @@ var CPViewHighDPIDrawingEnabled = YES;
return self;
}
/*!
Sets the tooltip for the receiver.
@@ -599,6 +603,7 @@ var CPViewHighDPIDrawingEnabled = YES;
// Remove the view from its previous superview.
[aSubview _removeFromSuperview];
[aSubview _postViewWillAppearNotification];
// Set ourselves as the superview.
[aSubview _setSuperview:self];
}
@@ -685,6 +690,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self window] _dirtyKeyViewLoop];
[_superview willRemoveSubview:self];
[self _postViewWillDisappearNotification];
[_superview._subviews removeObjectIdenticalTo:self];
@@ -1616,18 +1622,40 @@ var CPViewHighDPIDrawingEnabled = YES;
while (view = [view superview]);
}
[self _postViewWillDisappearNotification];
[self _recursiveGainedHiddenAncestor];
}
else
{
[self setNeedsDisplay:YES];
[self _postViewWillAppearNotification];
[self _recursiveLostHiddenAncestor];
}
_isHidden = aFlag;
}
- (void)_postViewWillAppearNotification
{
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewWillAppearNotification object:self userInfo:nil];
}
- (void)_postViewDidAppearNotification
{
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewDidAppearNotification object:self userInfo:nil];
}
- (void)_postViewWillDisappearNotification
{
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewWillDisappearNotification object:self userInfo:nil];
}
- (void)_postViewDidDisappearNotification
{
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewDidDisappearNotification object:self userInfo:nil];
}
- (void)_setSuperview:(CPView)aSuperview
{
var hasOldSuperview = (_superview !== nil),
@@ -1636,12 +1664,18 @@ var CPViewHighDPIDrawingEnabled = YES;
newSuperviewIsHidden = hasNewSuperview && [aSuperview isHiddenOrHasHiddenAncestor];
if (!newSuperviewIsHidden && oldSuperviewIsHidden)
[self _recursiveLostHiddenAncestor];
[self _recursiveLostHiddenAncestor];
if (newSuperviewIsHidden && !oldSuperviewIsHidden)
[self _recursiveGainedHiddenAncestor];
_superview = aSuperview;
if (hasOldSuperview)
[self _postViewDidDisappearNotification];
if (hasNewSuperview)
[self _postViewDidAppearNotification];
}
- (void)_recursiveLostHiddenAncestor
@@ -3669,7 +3703,6 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
_window = [aCoder decodeObjectForKey:CPViewWindowKey];
_superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
// We have to manually add the subviews so that they will receive
// viewWillMoveToSuperview: and viewDidMoveToSuperview:
_subviews = [];
+34 -4
View File
@@ -213,7 +213,7 @@ var CPViewControllerCachedCibs;
if (anError == nil)
{
var data = [CPData dataWithRawString:aData],
aCib = [[CPCib alloc] _initWithData:data bundle:_cibBundle cibName:_cibName];
aCib = [[CPCib alloc] _initWithData:data bundle:_cibBundle cibName:_cibName];
[CPViewControllerCachedCibs setObject:aCib forKey:_cibName];
[aCib instantiateCibWithExternalNameTable:_cibExternalNameTable];
@@ -286,13 +286,16 @@ var CPViewControllerCachedCibs;
- (void)_viewDidLoad
{
[self _viewDidLoadWithCompletionHandler:function() {
[self viewDidLoad];
}];
[self willChangeValueForKey:"isViewLoaded"];
[self viewDidLoad];
_isViewLoaded = YES;
[self didChangeValueForKey:"isViewLoaded"];
}
- (void)_viewDidLoadWithCompletionHandler:(Function)aHandler
{
[self _registerOrUnregister:YES notificationsForView:_view];
[self willChangeValueForKey:"isViewLoaded"];
aHandler(_view, nil);
_isViewLoaded = YES;
@@ -325,6 +328,9 @@ var CPViewControllerCachedCibs;
{
var willChangeIsViewLoaded = (_isViewLoaded == NO && aView != nil) || (_isViewLoaded == YES && aView == nil);
[self _registerOrUnregister:NO notificationsForView:_view];
[self _registerOrUnregister:YES notificationsForView:aView];
if (willChangeIsViewLoaded)
[self willChangeValueForKey:"isViewLoaded"];
@@ -340,6 +346,30 @@ var CPViewControllerCachedCibs;
return NO;
}
- (void)_registerOrUnregister:(BOOL)shouldRegister notificationsForView:(CPView)aView
{
if (aView === nil)
return;
var center = [CPNotificationCenter defaultCenter],
notifs_to_sel = @{_CPViewWillAppearNotification : @"viewWillAppear",
_CPViewDidAppearNotification : @"viewDidAppear",
_CPViewWillDisappearNotification : @"viewWillDisappear",
_CPViewDidDisappearNotification : @"viewDidDisappear"};
[notifs_to_sel enumerateKeysAndObjectsUsingBlock:function(notif, selString, stop)
{
var selector = CPSelectorFromString(selString);
if ([self implementsSelector:selector])
{
if (shouldRegister)
[center addObserver:self selector:selector name:notif object:aView];
else
[center removeObserver:self name:notif object:aView];
}
}];
}
@end
+10
View File
@@ -0,0 +1,10 @@
<?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>Main cib file base name</key>
<string>MainMenu.cib</string>
<key>CPBundleName</key>
<string>BundleTest</string>
</dict>
</plist>
@@ -0,0 +1 @@
280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;0E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;4E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;0E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;1;7E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;1;9E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;11E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;13E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;15E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;18E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;11E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;19E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;12E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;20E;E;D;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;11E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;18E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;21E;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;22E;E;D;K;10;$classnameS;18;_CPCibClassSwapperK;8;$classesA;S;18;_CPCibClassSwapperS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;17E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;24E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;24E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;25E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;1;0E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;26E;K;14;CPViewScaleKeyD;K;6;CP$UIDd;2;27E;K;18;CPViewSizeScaleKeyD;K;6;CP$UIDd;2;27E;K;17;CPViewIsScaledKeyD;K;6;CP$UIDd;2;28E;K;19;CPViewAppearanceKeyD;K;6;CP$UIDd;1;0E;K;22;CPViewTrackingAreasKeyD;K;6;CP$UIDd;2;29E;K;30;_CPCibClassSwapperClassNameKeyD;K;6;CP$UIDd;2;30E;K;38;_CPCibClassSwapperOriginalClassNameKeyD;K;6;CP$UIDd;2;31E;E;S;16;CPViewControllerD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;4;viewS;13;CPApplicationd;1;0S;20;{{0, 0}, {480, 272}}d;2;12S;6;normalS;6;{1, 1}F;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;6;NSViewS;6;CPViewE;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E;
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10116"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="CPViewController">
<connections>
<outlet property="view" destination="c22-O7-iKe" id="ABk-lK-Kp8"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="c22-O7-iKe">
<rect key="frame" x="0.0" y="0.0" width="480" height="272"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</customView>
</objects>
</document>
+89
View File
@@ -0,0 +1,89 @@
@import <AppKit/CPViewController.j>
@import <AppKit/CPApplication.j>
var methodsCalled;
@implementation CPViewControllerTest : OJTestCase
{
CPBundle bundle;
}
- (void)setUp
{
bundle = [CPBundle bundleWithPath:@"Tests/AppKit/BundleTest"];
[bundle loadWithDelegate:self];
}
- (void)bundleDidFinishLoading:(CPBundle)aBundle
{
}
- (void)testViewControllerCallbacks
{
methodsCalled = @[];
var expectedResult = @[@"viewDidLoad",
@"viewWillAppear",
@"viewDidAppear",
@"viewWillDisappear",
@"viewDidDisappear"];
[self assertTrue:[bundle isLoaded]];
var viewController = [[ViewController alloc] initWithCibName:@"NSViewController.cib" bundle:bundle];
[self assertNotNull:viewController];
var superview = [[CPView alloc] initWithFrame:CGRectMakeZero()];
var view = [viewController view];
[superview addSubview:view];
[view removeFromSuperview];
[self assert:expectedResult equals:methodsCalled];
// Explicitely change the view.
methodsCalled = [];
expectedResult = @[@"viewWillAppear",
@"viewDidAppear",
@"viewWillDisappear",
@"viewDidDisappear"];
var newView = [[CPView alloc] initWithFrame:CGRectMake(0,0,100,100)];
[viewController setView:newView];
[superview addSubview:newView];
[newView removeFromSuperview];
// Checks that with receive notifs from the new view and not from the old view.
[self assert:expectedResult equals:methodsCalled];
}
@end
@implementation ViewController : CPViewController
{
}
- (void)viewDidLoad
{
[methodsCalled addObject:_cmd];
}
- (void)viewDidAppear
{
[methodsCalled addObject:_cmd];
}
- (void)viewWillAppear
{
[methodsCalled addObject:_cmd];
}
- (void)viewDidDisappear
{
[methodsCalled addObject:_cmd];
}
- (void)viewWillDisappear
{
[methodsCalled addObject:_cmd];
}
@end
+19 -2
View File
@@ -905,6 +905,21 @@ var updateTrackingAreasCalls,
[self assert:expectedResult equals:methodCalled];
}
- (void)testAddViewRemoveView
{
var expectedResult = [@"viewWillMoveToSuperview_view2",
@"viewDidMoveToSuperview_view2",
@"viewWillMoveToSuperview_view2",
@"viewDidMoveToSuperview_view2",
@"viewWillMoveToWindow_view2",
@"viewDidMoveToWindow_view2"];
[view1 addSubview:view2];
[view2 removeFromSuperview];
[self assert:expectedResult equals:methodCalled];
}
- (void)testViewGainedHiddenAncestor
{
var expectedResult = [@"viewDidHide_view1",
@@ -917,14 +932,16 @@ var updateTrackingAreasCalls,
[view1 setHidden:YES];
[view2 addSubview:view3];
CPLog.warn("will add view2");
[view1 addSubview:view2];
[self assert:expectedResult equals:methodCalled];
[self assertTrue: [view2 isHiddenOrHasHiddenAncestor] message:@"Expected isHiddenOrHasHiddenAncestor = YES"];
[self assertTrue: [view2 isHiddenOrHasHiddenAncestor] message:@"Expected " + [view2 identifier] + "isHiddenOrHasHiddenAncestor = YES"];
[self assertTrue: [view3 isHiddenOrHasHiddenAncestor] message:@"Expected isHiddenOrHasHiddenAncestor = YES"];
[self assertFalse:[view2 isHidden]];
[self assertFalse:[view3 isHidden]];
[self assert:expectedResult equals:methodCalled];
}
- (void)testRemoveViewsHiddenByAncestor