I have an NSTextField
subclass which uses a NSTextFieldCell
subclass which contains an attributed string. I would like it if when the user copies text that it be copied to the pasteboard without the attributes.
I have tried subclassing NSTextView
, overriding copy:
and setting isFieldEditor
to YES
and returning this new editor from the cells fieldEditorForView
method. While this copies only the plain text whenever it is used I have text drawn on text drawn on text (and so on ...) and if the underlying attributed string is changed by another control the field editor remains unmodified. When I do not use MyFieldEditor
and let the NSTextFieldCell
subclass use the default implementation this issue does not occur.
Is there a simpler solution to this problem?
Is there something additional that I need to override or receive delegate messages for?
MyFieldCell.m
- (NSTextView *)fieldEditorForView:(NSView *)controlView
{
MyFieldEditor *editor = [[MyFieldEditor alloc] init];
[super setUpFieldEditorAttributes:editor];
return editor;
}
MyFieldEditor.m
@implementation MyFieldEditor
- (instancetype)init
{
if ( (self = [super init]) )
{
[self setFieldEditor:YES];
}
return self;
}
- (NSString *)selectedString
{
return [[self string] substringWithRange:[self selectedRange]];
}
- (void)copy:(id)sender
{
[[NSPasteboard generalPasteboard] setString:[self selectedString] forType:NSPasteboardTypeString];
}
@end
Note: I am using ARC.
Please find below what should be changed. Tested & works with Xcode 11.2.1 / macOS 10.15.2 with no display issues.
a) No custom NSTextFieldCell
and NSTextField
are needed, so used just default
b) Change to following in MyFieldEditor.m
- (void)copy:(id)sender
{
[NSPasteboard.generalPasteboard declareTypes:@[NSPasteboardTypeString] owner:self];
[NSPasteboard.generalPasteboard setString:[self selectedString] forType:NSPasteboardTypeString];
}
c) Add window delegate method substituting field editor for targeted textfield (this is the valid documented way to provide custom field editors)
- (nullable id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(nullable id)client {
if (client == self.textField) { // << in this case it is outlet
return MyFieldEditor.new;
}
return nil;
}
Update:
Overriding NSTextFieldCell as below and assigning it in XIB for targeted NSTextField instead of above NSWindow delegate method gives the same valid behaviour.
@interface MyTextCell: NSTextFieldCell
@end
@implementation MyTextCell
- (nullable NSTextView *)fieldEditorForView:(NSView *)controlView {
id editor = MyFieldEditor.new;
[super setUpFieldEditorAttributes:editor];
return editor;
}
@end