mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-24 09:08:53 +00:00
AppKit: Disable Undo and Redo when a text view does not allow undo
A text view handled undo: and redo: and registered its changes even when allowsUndo was NO, so Edit > Undo stayed enabled and did nothing. Behaviour now follows canonical Cocoa: a text view that does not allow undo registers nothing and passes undo: and redo: on to the window, and Undo and Redo are enabled only when there is a change to undo or redo. * CPTextView/CPTextView.j: Register changes only when undo is allowed, stop responding to undo: and redo: when it is not, and validate the Undo and Redo items against the undo manager. * CPWindow/CPWindow.j: Validate the Undo and Redo items against the window's undo manager. * Tests/AppKit/CPTextViewTest.j: Add tests for responding to undo:, registering changes and validating the Undo item. * Tests/Manual/TextEditor/DocumentWindowController.j: Add toggleAllowsUndo: and validateMenuItem:, so that undo can be turned on and off for the active document. * Tests/Manual/TextEditor/Resources/MainMenu.xib, Resources/MainMenu.cib: Add Edit > Allow Undo. * Tests/Manual/TextEditor/WORKLIST.md: Remove the entry for this gap, record Allow Undo as tested, and add the key equivalent behaviour of disabled menu items for discussion.
This commit is contained in:
1 parent
92b8039c71
commit
66ea130c8d
7 files changed
+171
-14
No files matched your search
@@ -688,6 +688,47 @@ var kDelegateRespondsTo_textShouldBeginEditing
|
||||
[[[self window] undoManager] redo];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Returns the undo manager that records the text view's changes, or nil when allowsUndo is NO,
|
||||
so that a text view that does not allow undo registers nothing.
|
||||
*/
|
||||
- (CPUndoManager)_registeringUndoManager
|
||||
{
|
||||
return _allowsUndo ? [[self window] undoManager] : nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
A text view that does not allow undo does not respond to \c -undo: or \c -redo:, so those
|
||||
actions continue along the responder chain to the window, as in Cocoa.
|
||||
*/
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
if (!_allowsUndo && (aSelector === @selector(undo:) || aSelector === @selector(redo:)))
|
||||
return NO;
|
||||
|
||||
return [super respondsToSelector:aSelector];
|
||||
}
|
||||
|
||||
/*!
|
||||
Enables the Undo and Redo items only when the undo manager has a change to undo or redo.
|
||||
Every other item is enabled.
|
||||
@param anItem the item to validate
|
||||
@return \c YES if the item should be enabled
|
||||
*/
|
||||
- (BOOL)validateUserInterfaceItem:(id /*<CPValidatedUserInterfaceItem>*/)anItem
|
||||
{
|
||||
var action = [anItem action];
|
||||
|
||||
if (action === @selector(undo:))
|
||||
return [[[self window] undoManager] canUndo];
|
||||
|
||||
if (action === @selector(redo:))
|
||||
return [[[self window] undoManager] canRedo];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
// MARK: -
|
||||
// MARK: Accessors
|
||||
@@ -818,7 +859,7 @@ var kDelegateRespondsTo_textShouldBeginEditing
|
||||
|
||||
- (void)_replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPString)aString selectionRange:(CPRange)selectionRange
|
||||
{
|
||||
[[[[self window] undoManager] prepareWithInvocationTarget:self]
|
||||
[[[self _registeringUndoManager] prepareWithInvocationTarget:self]
|
||||
_replaceCharactersInRange:CPMakeRange(aRange.location, [aString length])
|
||||
withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(aRange)]
|
||||
selectionRange:CPMakeRangeCopy(_selectionRange)];
|
||||
@@ -840,7 +881,7 @@ var kDelegateRespondsTo_textShouldBeginEditing
|
||||
else if (![self isRichText])
|
||||
aString = [[CPAttributedString alloc] initWithString:string attributes:_typingAttributes];
|
||||
|
||||
var undoManager = [[self window] undoManager];
|
||||
var undoManager = [self _registeringUndoManager];
|
||||
[undoManager setActionName:@"Replace/insert text"];
|
||||
|
||||
[[undoManager prepareWithInvocationTarget:self]
|
||||
@@ -1692,7 +1733,7 @@ Sets the selection to a range of characters in response to user action.
|
||||
|
||||
changedRange = CPIntersectionRange(CPMakeRange(0, [_layoutManager numberOfCharacters]), changedRange);
|
||||
|
||||
[[[_window undoManager] prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(changedRange.location, 0)
|
||||
[[[self _registeringUndoManager] prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(changedRange.location, 0)
|
||||
withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(changedRange)]
|
||||
selectionRange:CPMakeRangeCopy(_selectionRange)];
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
@@ -1879,7 +1920,7 @@ Sets the selection to a range of characters in response to user action.
|
||||
|
||||
var currentAttributes = [_textStorage attributesAtIndex:range.location effectiveRange:nil] || _typingAttributes;
|
||||
|
||||
[[[[self window] undoManager] prepareWithInvocationTarget:self]
|
||||
[[[self _registeringUndoManager] prepareWithInvocationTarget:self]
|
||||
setFont:[currentAttributes objectForKey:CPFontAttributeName] || [self font]
|
||||
range:CPMakeRangeCopy(range)];
|
||||
|
||||
@@ -1893,7 +1934,7 @@ Sets the selection to a range of characters in response to user action.
|
||||
oldFont,
|
||||
attributes,
|
||||
scrollRange = CPMakeRange(CPMaxRange(_selectionRange), 0),
|
||||
undoManager = [[self window] undoManager];
|
||||
undoManager = [self _registeringUndoManager];
|
||||
|
||||
[undoManager beginUndoGrouping];
|
||||
|
||||
@@ -1957,7 +1998,7 @@ Sets the selection to a range of characters in response to user action.
|
||||
{
|
||||
var currentAttributes = [_textStorage attributesAtIndex:range.location effectiveRange:nil] || _typingAttributes;
|
||||
|
||||
[[[[self window] undoManager] prepareWithInvocationTarget:self]
|
||||
[[[self _registeringUndoManager] prepareWithInvocationTarget:self]
|
||||
setTextColor:[currentAttributes objectForKey:CPForegroundColorAttributeName] || _textColor
|
||||
range:CPMakeRangeCopy(range)];
|
||||
|
||||
@@ -2031,7 +2072,7 @@ Sets the selection to a range of characters in response to user action.
|
||||
if (_selectionRange.length > 0)
|
||||
{
|
||||
// Add rudimentary undo support
|
||||
var undoManager = [[self window] undoManager];
|
||||
var undoManager = [self _registeringUndoManager];
|
||||
if (undoManager)
|
||||
{
|
||||
[[undoManager prepareWithInvocationTarget:self]
|
||||
|
||||
@@ -2830,13 +2830,22 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
For \c -toggleToolbarShown:, the item's title becomes "Hide Toolbar" or "Show Toolbar"
|
||||
to reflect the toolbar's visibility, and the item is enabled only when the window has
|
||||
a toolbar. Every other item is enabled.
|
||||
a toolbar. \c -undo: and \c -redo: are enabled only when the window's undo manager has a
|
||||
change to undo or redo. Every other item is enabled.
|
||||
@param anItem the item to validate
|
||||
@return \c YES if the item should be enabled
|
||||
*/
|
||||
- (BOOL)validateUserInterfaceItem:(id /*<CPValidatedUserInterfaceItem>*/)anItem
|
||||
{
|
||||
if ([anItem action] !== @selector(toggleToolbarShown:))
|
||||
var action = [anItem action];
|
||||
|
||||
if (action === @selector(undo:))
|
||||
return [[self undoManager] canUndo];
|
||||
|
||||
if (action === @selector(redo:))
|
||||
return [[self undoManager] canRedo];
|
||||
|
||||
if (action !== @selector(toggleToolbarShown:))
|
||||
return YES;
|
||||
|
||||
var toolbar = [self toolbar];
|
||||
|
||||
@@ -136,6 +136,56 @@
|
||||
[delegateSpy verifyThatAllExpectationsHaveBeenMet];
|
||||
}
|
||||
|
||||
- (void)testTextViewRespondsToUndoOnlyWhenUndoIsAllowed
|
||||
{
|
||||
[textView setAllowsUndo:YES];
|
||||
|
||||
[self assertTrue:[textView respondsToSelector:@selector(undo:)]];
|
||||
[self assertTrue:[textView respondsToSelector:@selector(redo:)]];
|
||||
|
||||
[textView setAllowsUndo:NO];
|
||||
|
||||
[self assertFalse:[textView respondsToSelector:@selector(undo:)] message:@"undo: should continue to the window"];
|
||||
[self assertFalse:[textView respondsToSelector:@selector(redo:)] message:@"redo: should continue to the window"];
|
||||
}
|
||||
|
||||
- (void)testTextViewRegistersUndoOnlyWhenUndoIsAllowed
|
||||
{
|
||||
var undoManager = [theWindow undoManager];
|
||||
|
||||
[self assertTrue:[theWindow makeFirstResponder:textView]];
|
||||
|
||||
[textView setAllowsUndo:NO];
|
||||
[undoManager removeAllActions];
|
||||
[textView insertText:@"Not recorded"];
|
||||
|
||||
[self assertFalse:[undoManager canUndo] message:@"a text view that does not allow undo should register nothing"];
|
||||
|
||||
[textView setAllowsUndo:YES];
|
||||
[textView insertText:@"Recorded"];
|
||||
|
||||
[self assertTrue:[undoManager canUndo] message:@"a text view that allows undo should register its change"];
|
||||
}
|
||||
|
||||
- (void)testUndoItemIsEnabledOnlyWhenThereIsAChangeToUndo
|
||||
{
|
||||
var undoManager = [theWindow undoManager],
|
||||
undoItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@""],
|
||||
redoItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@""];
|
||||
|
||||
[self assertTrue:[theWindow makeFirstResponder:textView]];
|
||||
[undoManager removeAllActions];
|
||||
|
||||
[self assertFalse:[textView validateUserInterfaceItem:undoItem]];
|
||||
[self assertFalse:[theWindow validateUserInterfaceItem:undoItem]];
|
||||
[self assertFalse:[textView validateUserInterfaceItem:redoItem]];
|
||||
|
||||
[textView insertText:@"Recorded"];
|
||||
|
||||
[self assertTrue:[textView validateUserInterfaceItem:undoItem]];
|
||||
[self assertTrue:[theWindow validateUserInterfaceItem:undoItem]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTextViewTest (CPTextViewTestDelegate)
|
||||
|
||||
@@ -123,4 +123,51 @@ var DocumentWindowMinimumWidth = 360.0,
|
||||
Math.max(aSize.height, DocumentWindowMinimumHeight));
|
||||
}
|
||||
|
||||
/*!
|
||||
Turns undo on or off for this document's text view.
|
||||
|
||||
This is test scaffolding, not a Cocoa convention: Cocoa apps set
|
||||
allowsUndo once, in Interface Builder or in code. The Edit > Allow Undo
|
||||
menu item exists so that both settings can be tried while the app runs.
|
||||
It will move to a Settings window.
|
||||
|
||||
Like Insert Lorem Ipsum, the menu item sends its action to First
|
||||
Responder, and the responder chain delivers it to the controller of the
|
||||
active document's window. Neither the text view nor the window responds
|
||||
to toggleAllowsUndo:, so the action passes them by.
|
||||
*/
|
||||
- (@action)toggleAllowsUndo:(id)aSender
|
||||
{
|
||||
var allowsUndo = ![textView allowsUndo];
|
||||
|
||||
[textView setAllowsUndo:allowsUndo];
|
||||
|
||||
/*
|
||||
A text view that does not allow undo registers no changes, and does
|
||||
not respond to undo: or redo:, so those actions go on to the window
|
||||
and its undo manager. Remove the changes the text view registered
|
||||
before undo was turned off, so that Edit > Undo cannot still undo
|
||||
them through the window.
|
||||
*/
|
||||
if (!allowsUndo)
|
||||
[[[self window] undoManager] removeAllActionsWithTarget:textView];
|
||||
}
|
||||
|
||||
/*!
|
||||
Validates the menu items whose actions this controller handles.
|
||||
|
||||
AppKit calls this method before it shows a menu, for each item whose
|
||||
action reaches this controller through the responder chain. For Allow
|
||||
Undo, it sets the item's check mark from the active document's text
|
||||
view, so the mark follows the document whose window is in front. Every
|
||||
item is enabled.
|
||||
*/
|
||||
- (BOOL)validateMenuItem:(CPMenuItem)aMenuItem
|
||||
{
|
||||
if ([aMenuItem action] === @selector(toggleAllowsUndo:))
|
||||
[aMenuItem setState:[textView allowsUndo] ? CPOnState : CPOffState];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1 +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;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;18E;D;K;6;CP$UIDd;2;19E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;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;50E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;D;K;6;CP$UIDd;2;58E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;69E;D;K;6;CP$UIDd;2;70E;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;74E;D;K;6;CP$UIDd;2;75E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;2;78E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;80E;D;K;6;CP$UIDd;2;81E;D;K;6;CP$UIDd;2;82E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;86E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;2;96E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;98E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;103E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;3;107E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;112E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;115E;D;K;6;CP$UIDd;3;116E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;118E;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;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;96E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;3;115E;D;K;6;CP$UIDd;3;116E;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;3;119E;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;3;120Line truncated
|
||||
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;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;18E;D;K;6;CP$UIDd;2;19E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;50E;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;51E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;D;K;6;CP$UIDd;2;58E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;69E;D;K;6;CP$UIDd;2;70E;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;74E;D;K;6;CP$UIDd;2;75E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;2;78E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;80E;D;K;6;CP$UIDd;2;81E;D;K;6;CP$UIDd;2;82E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;86E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;2;96E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;98E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;103E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;3;107E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;112E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;115E;D;K;6;CP$UIDd;3;116E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;118E;D;K;6;CP$UIDd;3;119E;D;K;6;CP$UIDd;3;120E;D;K;6;CP$UIDd;3;121E;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;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;86E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;3;112E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;3;118E;D;K;6;CP$UIDd;3;119E;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;3;122E;E;D;K;10;$classnameS;5;CPSetK;8;Line truncated
|
||||
@@ -99,6 +99,15 @@
|
||||
<menuItem isSeparatorItem="YES" id="206">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Allows Undo" id="KpR-5r-W4E">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAllowsUndo:" target="-1" id="zMx-wC-uNv"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="cis-d4-OoI">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="199">
|
||||
<connections>
|
||||
<action selector="cut:" target="-1" id="228"/>
|
||||
|
||||
@@ -20,10 +20,6 @@ TextEditor is a document-based test application and a tutorial. When the app use
|
||||
- **`CPTextView` has no ruler control API.** `usesRuler`, `setUsesRuler:`, `setRulerVisible:` and `toggleRuler:` do not exist. `isRulerVisible` always returns `NO` (`CPTextView.j:2088`).
|
||||
- **`CPRulerMarker` ignores `markerLocation`.** `initWithRulerView:markerLocation:imageValue:representedObject:` uses `imageValue` as the location.
|
||||
|
||||
### Undo and redo
|
||||
|
||||
- **Undo stays enabled when `allowsUndo` is `NO`.** `-[CPTextView undo:]` then does nothing (`CPTextView.j:679`). The text view must disable the menu item in that case.
|
||||
|
||||
### Clipboard
|
||||
|
||||
- **Paste and Cut from the Edit menu do nothing.** `-[CPTextView paste:]` (`CPTextView.j:521`) and `cut:` (`:1754`) return unless the current event is `CPAppKitDefined`. Only the browser's native clipboard events, from the keyboard, create that event.
|
||||
@@ -43,6 +39,10 @@ TextEditor is a document-based test application and a tutorial. When the app use
|
||||
|
||||
- **The content view's resizing setting does not reach the cib.** Making the document window's content view resize with the window in `DocumentWindow.xib` produces a byte-identical `DocumentWindow.cib`. CPView omits the autoresizing mask from the archive only when it is `CPViewNotSizable` (`CPView.j:4016`), so the content view is archived as not sizable. Not yet determined whether `ibtool` or nib2cib drops the setting. The app still behaves correctly, because the window resizes its content view itself.
|
||||
|
||||
### Menus and key equivalents (needs discussion)
|
||||
|
||||
- **The key equivalent of a disabled menu item reaches the browser.** `-[CPMenu performKeyEquivalent:]` (`CPMenu.j:1059`) stops the browser's default action only when the matching item is enabled. For a disabled item it reports the key as handled, but the browser still acts on it: with File > Close disabled, Cmd-W closes the browser tab. Cocoa consumes the key equivalent of a disabled item with a beep. Stopping the browser's default for disabled items as well would match Cocoa for most keys, but not all: some browsers do not let a page block certain shortcuts, such as Cmd-W, Cmd-N and Cmd-T in Chrome, and Copy, Cut and Paste must keep reaching the browser for its clipboard events. This needs careful thought, and perhaps discussion, before any change.
|
||||
|
||||
### Platform
|
||||
|
||||
- **Key equivalents on platforms other than macOS.** Filed as an issue.
|
||||
@@ -70,4 +70,5 @@ TextEditor is a document-based test application and a tutorial. When the app use
|
||||
- View > Show Toolbar and Hide Toolbar: the item's title follows the toolbar's visibility.
|
||||
- The Window menu lists the open document windows, marks the main window with a check mark and brings a window to the front when chosen. Bring All to Front can be tested once documents open in separate browser windows.
|
||||
- The About panel shows the display name from `CPBundleDisplayName`.
|
||||
- Edit > Allow Undo turns undo on and off for the active document. With undo off, Undo and Redo stay disabled, and the check mark follows the document in front.
|
||||
- Builds with both the legacy toolchain and capp-build.
|
||||
Reference in new issue
Block a user