NSTextView / NSScrollView - A few questions to help me understand it's proper usage - xcode

I have created a "notes" field designed to hold multiple paragraphs of text which I would like to store in a custom object. Originally, I just used an NSTextField as a temporary solution, but this does not allow me to scroll or have multiple paragraphs of text...
In IB I have placed a NSTextView (which seems to be wrapped inside an NSScrollView.) Upon execution of my program, seems to allow me to enter text in multiple paragraphs, scroll, etc. In short it LOOKS to be exactly what I want would like it to be. So far so good.
Now, I need to retrieve the data from this field and store it in my custom object. This is where I'm getting a bit lost within the developer documentation...
My goals are fairly straight forward:
Allow users to type away in the box.
Store the contents of the box into a variable (array, etc.) in my custom object when the user moves to another field, leaving the notes field.
Display the users stored text in the text box next time the record is viewed.
Second, is there a simple way to retrieve and store the data into a "notes" variable in my custom object (such as an NSString object? I would think having multiple would exclude an NSString object as an option here, but maybe I'm wrong) or am I getting into a more complex area here (such as having to store it in an array of NSString objects, etc.)?
Any help would be appreciated!

You can get the data using -string, defined by NSText (e.g. NSString *savedString = [aTextView string])
Your save code can be put in your NSTextDelegate (read, delegate of the NSTextView, because it's the immediate superclass), in – textDidEndEditing: which will be called, well, when editing is finished (e.g. when the user clicks outside the view) or one of the other methods.
Then to reload the saved string if you emptied the text view or something, use [textView setString:savedString] before editing begins.
NSTextDelegate documentation: here.
I'm not sure what you mena when you say "store the contents of the box into a variable (array, etc.) Are you hoping for an array of custom notes? Text views store a string of data, so the easiest way of storing its value is using one string; if you need an array of notes you'd have to split the string value into different paragraphs, which shouldn't be too hard.

Related

Search for an NSView inside a NIB by string

I'm trying to write an application which should display some data. The data in question comes from a different module in our code (written in C, not ObjC), and for various reasons is identified by a string, not an integer or other form of constant. After the glue code, I have an incoming method on my AppDelegate like so:
-(void)newstringdata:(NSString*)data withLabel:(NSString*)label;
This method should always take the value of data and set it as the text for a particular label in the UI. The problem is, which label.
I could of course create an NSDictionary and fill it at run time with the possible values for the label parameter in the newstringdata:withLabel: method and references to outlets, but this seems somewhat ugly and inefficient; it requires me to maintain the outlets, the nib, and the NSDictionary-initializing code.
Instead, if possible, I would like to set a property in the interface designer somewhere, and then do a lookup in my newstringdata:withLabel: method based on the label which was passed which returns the NSLabel.
Is this possible? If so, how would I do it?
If the value of label will never include a slash (/), backslash (\), or colon (:), you can use the identifier property of NSView.
In the xib, enter each label string as the NSTextViews's identifier (in the Identity tab, 3rd tab from left).
Then in your code, loop through all views and:
if ([aView.identifier isEqualToString:label])
[aView setStringValue:data];

Removing text from NSTextView

I have created an NSTextView and managed to populate it using a getter for the scroll view that it is nested in, and using the .insertText() function.
How do I empty the same NSTextView? I have read the documentation and there doesn't seem to be a function .removeText(). It seems a bit weird that Apple would allow you to insert data but not remove it programmatically. I have searched high and low for answers but have come up empty handed.
You can't set the text of the text view directly, but you can set its textStorage's, getting that object's mutableString, which it inherits from NSMutableAttributedString, and then using setString(), passing an empty string.
No idea what I was thinking. Use var string { get set }, inherited from NSText.
If you set the text on the textview directly you'll lose the ability to automatically have the undo manager pick that change up.
I've found it more reliable to first select all the text and then delete it.
[self.textInput selectAll:self];
[self.textInput delete:self];

NSTextView in NSPersistentDocument doesn't update dirty flag until loses first responder

I have an NSTextView in an NSPersistentDocument window. I bind the text field's contents to a "binary data" Core Data field, but when I type text into the text view, the document's title bar doesn't say "Edited" until the text view loses focus. Thus, if I quit after making an edit, the new data isn't saved.
If I pass the NSContinuouslyUpdatesValueBindingOption flag to the text view binding, "Edited" appears immediately, but performance really suffers in long documents.
How do I let Core Data know that there are unsaved changes without actually assigning all the text data on every change?
(This question is like "Binded NSTextField doesn't update the entity until it lose the focus" except I can't use NSContinuouslyUpdatesValueBindingOption because it makes editing operations very slow.)
I think this is not possible as far as i understood.
When you assign the changes to a property of a NSManagnedObject, CoreData manage to diry state (and the undo stuff) for you. If you just try to change the diry without the data a potential save operation will not work.
Take a look into "The Document Architecture Provides Undo Support for Free" how the dirty state and the undo support are implemented.
If you have really large text documents, i suggest you should not store them in a CoreData property. As you can read in "Incremental Data Reading and Writing" i suggest to store the text in a separate file and use a NSFileWrapper. At least I use this solution for my application.
This is btw. what CoreData itself suggest here "...It is better, however, if you are able to store BLOBs as resources on the filesystem, and to maintain links (such as URLs or paths) to those resources. You can then load a BLOB as and when necessary"
I don't know what kind of text you have in your NSTextView but you was taking about "long documents".
If you subclass your "NSTextView", you can catch the "insertText:" method and then as soon as a character is typed, set the "document Edited" flag of the document without the heavy duty (and CPU intensive) binding you're doing.

(Mac OS X, Cocoa) How to make drag-and-droppable placeholder elements in an input text field?

I'm writing a Cocoa app where I would like the user to be able to put together a template string using placeholders. (For example, an (artist) placeholder would be filled in by the artist of the song currently playing in iTunes, etc.) I've seen apps that do something like this where each possible placeholder term is displayed in a blue "lozenge," and the user can drag and drop these "lozenges" into an input text field to construct a string, optionally entering some custom text of their own (e.g. separating (artist) and (title) "lozenges" with a hyphen).
Does anyone know if there is any sample code anywhere that will help me implement something like this?
I'm talking about something like this: (this comes from the "Hazel" app where, in a Hazel rule, you can rename a file based on a template pattern you specify)
NSTokenField is focused in the above pic (has the blue ring around it). Each "token" (your lozenges) is an auto-recognized string for the token field. As rdelmar comments above, read up on NSTokenField and you'll be most of the way there.
The "source" of tokens is likely a rounded-edged NSBox containing lined-up borderless, no-background NSTokenFields with one token each. That'll give you easy drag-and-drop as well as easy alignment.
if you need to customize the l&f of the individual tokens, you need to implement your own stuff: NSTextView with NSTextAttachment which have NSTextAttachmentCells... Its painful and a lot of code but actually not that hard
The NSTokenAttachment cell only has lots of private l&f options :(

Change cell content in NSTableView before editing

I have an NSTableView that allows inline editing on one of its cells (NSTextFieldCell). This actually works well, but I want to manipulate the content for the editing session.
Imagine having a string with a path (say: "folder/subfolder/myfile.txt") as the content of such a cell. But when the user enters edit mode for this cell (e.g. by double clicking) I want only the string "myfile.txt" to be editable (i.e. to appear in the editor). How can I achieve this?
You could create a custom NSFormatter that does this. Override the method stringForObjectValue: to return the full string and editingStringForObjectValue: to return only the part you want to edit. You also need to write a method getObjectValue:forString:errorDescription: to transform the edited string back to the complete string. How to exactly do this depends on the rest of your program. You somehow need to get back the part of the string you removed for editing.

Resources