views:

34

answers:

4

A user selects a song in my mp3 player. He proceeds to rename a song (thus highlighting the "name" column of that given song).

Let's say he pastes in "The\nGreat\nSong". By default, if the string formatter doesn't allow newlines (which is what I want), the app will produce a beep.

How can I process the string before it is pasted? This is what I want: If the string is less than 200 characters long, and if it contains newlines, replace the newlines with spaces before the string actually gets pasted. If it is longer than 200 characters, just do what it would do by default (because I don't want the user accidentally pasting his PhD thesis in there).

How can one do something like that?

A: 
- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex

You can check anObject (usually it is NSString) value and decide should you agree with new value or not.

beefon
This method does not work, validation has already happened when this method is being called. In the OP's case, the input would have been rejected beforehand and this method would never be called.
Max Seelemann
A: 

Look up NSPasteBoard for getting what is copied. From there, do the string checking and decide if they can paste or not.

Scott Pfeil
It's from Mac, not iPhone.
beefon
woops sorry, use NSPasteBoard not UIPasteBoard, I edited my answer.
Scott Pfeil
Wouldn't use this method either. Where do you want to intercept the paste action? The paste would happen in a NStextView being the field editor. You'd have to alter it's class and intercept the action for pasting. I find this a bad idea, breaks modularity.
Max Seelemann
A: 

If you want to validate the user input, then use some of the delegate methods. I never did this on my own, it's just what I know from the header and the documentation. But this might already help you:

Have a look at textShouldEndEditing: method of NSTableView. This method is being called when the user want to finish editing data, just as in your case. You can override this method to do your changes. However, from the documentation it read like you don't even need to override, just to implement a delegate method, control:textShouldEndEditing:, that is being called on that occasion.

I'd go for the latter. Implement control:textShouldEndEditing: and see how it's being called. The first argument should actually be the table view, the second an NSTextView used for editing. Using editedRow and editedColumn you can get the cell being edited for the table view. Make your validation and simply change the text of the field editor being passed.

Max Seelemann
I don't want to validate when the user leaves the field editor. I want to validate upon paste. Because my formatter will not allow newlines to be pasted into the field editor in the first place. I must therefore somehow process the text *before* it is pasted.
Enchilada
Hmm, never mind. It seems kind of obvious to me now that I should do my processing in my NSFormatter subclass itself, of course.
Enchilada
Right, that's the other way to do it. Clumsy me to not have had that idea...
Max Seelemann
A: 

Turns out it was probably easiest to just edit my NSFormatter subclass itself. Here is my NSFormatter method, in case anyone is interested:

- (BOOL)isPartialStringValid:(NSString *)partial
            newEditingString:(NSString **)newString
            errorDescription:(NSString **)errorString
{
  *errorString = nil;
  *newString = nil;

  if ([partial containsIllegal])
  {
    NSBeep();
    return NO;
  }
  else if ([partial containsNewline])
  {
    if ([partial length] > 200)
    {
      NSBeep();
      return NO;
    }
    else
    {
      *newString = [partial stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
      return NO;
    }
  }
  else
    return YES;
}

Those two NSString category methods there are simply as follows:

- (BOOL)containsIllegal
{
  for (int i=0; i<[self length]; i++)
  {
    unichar currentChar = [self characterAtIndex:i];

    BOOL charIsIllegal = [[NSCharacterSet illegalCharacterSet] characterIsMember:currentChar];

    if (charIsIllegal)
      return YES;
  }
  return NO;
}

- (BOOL)containsNewline
{
  for (int i=0; i<[self length]; i++)
  {
    unichar currentChar = [self characterAtIndex:i];

    BOOL charIsNewLine = [[NSCharacterSet newlineCharacterSet] characterIsMember:currentChar];

    if (charIsNewLine)
      return YES;
  }
  return NO;
}
Enchilada