1

I am trying to copy the row of the NSTableView on clipboard. Here is my code:

- (void) copy:(id)sender
{
    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    // I get warning in the line bellow, unused variable changeCount
    NSInteger changeCount = [pasteboard clearContents];
    NSInteger row = [self.customersViewController.customersTableView selectedRow];
    NSTableColumn *columnFirstName = [self.customersViewController.customersTableView tableColumnWithIdentifier:@"firstName"];
    NSCell *cellFirstName = [columnFirstName dataCellForRow:row];
    NSArray *objectsToCopy = @[[cellFirstName stringValue]];
    // I get warning in the line bellow unused variable OK
    BOOL OK = [pasteboard writeObjects:objectsToCopy];
}

This code works, and if I select the row in the NSTableView, the content of the firstName column of the selected row is indeed on the pasteboard (I can paste the value in text editor).

However this code have couple of issues:

1. I get 2 warnings as you can see from my comments.I rewrite the code to get rid of the warnings like this. Is anything wrong with the way how I re-write the code?

 // warning one
 NSInteger changeCount = 0;
 changeCount = [pasteboard clearContents];

 // warning 2
 BOOL OK = NO;
 OK = [pasteboard writeObjects:objectsToCopy];
  1. In the code above I name specific which NSTableView I use

    ...self.customersViewController.customersTableViev....

However If the user switch the view, it may use some other NSTableView...how can I find out from which NSTableView the copy method should copy the row?

If I comment the line where I use specific NSTableView and try to use sender, my app crashes.

//NSInteger row = [self.customersViewController.customersTableView selectedRow];
NSInteger row = [sender selectedRow];

3.How could I write a loop to get all column names instead of specifically write them by hand one by one? I will not know which NSTableView is used anyway....

NSTableColumn *columnFirstName = [self.customersViewController.customersTableView tableColumnWithIdentifier:@"firstName"];
user2417624
  • 653
  • 10
  • 32
  • What do you want to paste, in which format and in which order? – Willeke Mar 15 '16 at 09:41
  • Answer to question 1: [how to mask an unwanted “Dead Store” warning in XCode?](http://stackoverflow.com/questions/5294761/how-to-mask-an-unwanted-dead-store-warning-in-xcode) – Willeke Mar 15 '16 at 09:43
  • Datasource or bindings? Cell based or view based? – Willeke Mar 15 '16 at 09:45
  • I want to paste all the cells values in the selected row, in the same order as are the columns in the NSTableView. I use binding, and the NSTableView is cell based. About the answer on the question1, I will review it again, since I didn't understand why the solution provided worked in that specific code. However I would rather like to hear comment on my code. – user2417624 Mar 15 '16 at 23:09

1 Answers1

2
  1. If you don't want the return value you can omit it.

  2. To make you code table view independent you can use firstResponder of the window. Alternatively you can implement copy: in a cubclass of NSTableView. sender is the menu item.

  3. NSTableView's property tableColumns is an array of NSTableColumn.

Here's what I did:

- (void)copy:(id)sender {
    NSResponder *firstResponder = self.window.firstResponder;
    if (firstResponder && [firstResponder isKindOfClass:[NSTableView class]]) {
        NSTableView *tableView = (NSTableView *)firstResponder;
        NSArrayController *arrayController = [[tableView infoForBinding:NSContentBinding] objectForKey:NSObservedObjectKey];
        // create an array of the keys and formatters of the columns
        NSMutableArray *keys = [NSMutableArray array];
        for (NSTableColumn *column in [tableView tableColumns]) {
            NSString *key = [[column infoForBinding:NSValueBinding] objectForKey:NSObservedKeyPathKey]; // "arrangedObjects.name"
            if (key) {
                NSRange range = [key rangeOfString:@"."];
                if (range.location != NSNotFound)
                    key = [key substringFromIndex:range.location + 1];
                NSFormatter *formatter = [[column dataCell] formatter];
                if (formatter)
                    [keys addObject:@{@"key":key, @"formatter":formatter}];
                else
                    [keys addObject:@{@"key":key}];
            }
        }
        // create a tab separated string
        NSMutableString *string = [NSMutableString string];
        for (id object in [arrayController selectedObjects]) {
            for (NSDictionary *dictionary in keys) {
                id value = [object valueForKeyPath:dictionary[@"key"]];
                if (value) {
                    NSFormatter *formatter = [dictionary objectForKey:@"formatter"];
                    if (formatter)
                        [string appendFormat:@"%@\t", [formatter stringForObjectValue:value]];
                    else
                        [string appendFormat:@"%@\t", value];
                }
                else
                    [string appendFormat:@"\t"];
            }
            [string replaceCharactersInRange:NSMakeRange([string length] - 1, 1) withString:@"\n"];
        }
        NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
        [pasteboard clearContents];
        [pasteboard setString:string forType:NSPasteboardTypeString];
    }
}
Willeke
  • 14,578
  • 4
  • 19
  • 47
  • Works like a charm. I will now study this code line by line, in hope that I will manage to learn how to solve similar issues in the future. Thanks. – user2417624 Mar 17 '16 at 00:14