textDidChange?

Scenario:

I am creating a user interface to assist in the renaming of a bunch of files. The goal is to ensure that each file ends up with a completely unique name. As each file is selected, a set of associated metadata fields are concatenated together to aid in compliance to new naming conventions. I call this the “derived” name.

A Panel window is presented with the “derived” file name, the “original” file name, and a Scroll View of all of the previously assigned file names.

The “derived” file name field is of the type “Search Field.”

The user can change the text in the Search Field and an attached predicate filters the Scroll View. If the text in the Search View matches a pre-existing value, a caution icon is shown and the “Apply” button is made inactive. Once the field contains a unique value, the icon is changed to a green light and the “Apply” button is made active.

This all works great except for a couple of instances.
A - When the Panel is first displayed, the derived value is inserted into the Search Field via setStringValue_()

B - If the user sees a file name in the Scroll View, they can double click on the row and its value is entered in the Search Field, again with setStringValue_(). The intention being that he/she will make minor additions in order to make it unique.

The problem is that in situations A and B, the predicate is not applied to filter the list since there was not a keystroke to invoke the predicate filtering.

I understand that I need to issue either a “textDidChange()” or “controlTextDidChange()” but I cannot seem to get the syntax to work.

SO, HERE IS WHERE THE REAL QUESTION COMES IN:

The Scroll View is assigned a Double Click Action via:

assignedFileNamesView's setDoubleAction_("assignedFileNamesDblClickEntry:")

This is the code executed upon the Double Click:

on assignedFileNamesDblClickEntry_(sender)
    tell assignedFileNamesArrayController to set fr to selectedObjects() as record
    assignedFileNameSearchField's setstringValue_(filename of fr)
   -- [everything works fine up to this point]
    assignedFileNameSearchField's controlTextDidChange_(WHAT OBJECT OR VALUE GOES HERE?)
end assignedFileNamesDblClickEntry_

If I need to instantiate my own controlTextDidChange_ function, what commands does it need to issue?

on controlTextDidChange_(aNotification)
– [WHAT DO I DO WITH THE NOTIFICATION?]
end controlTextDidChange_

FYI- Cocoa Configuration:
I have a Scroll View properly populated with three columns bound to the arrangedObjects of individual fields in an ArrayController which is populated by an Array read from a plist file.

The Search Field has its Search Predicate bound to the “assignedFileNamesArrayController”, controller key “filterPredicate” display name “FileName”, Predicate Format “FileName CONTAINS[cd] $value”

What you are wanting to do is to trigger a manual Key Value Observing notification. You do that by wrapping your setStringValue_ with willChangeValueForKey_ and didChangeValueForKey_. Probably something like this:

searchField's willChangeValueForKey_("stringValue") 
searchField's setStringValue_("blah")
searchField's didChangeValueForKey_("stringValue") 

Hmmm. Didn’t work…

Per your suggestion, I tried the following as the DoubleClick Code:

on assignedFileNamesDblClickEntry_(sender)
    tell assignedFileNamesArrayController to set fr to selectedObjects() as record
    log fr
    assignedFileNameSearchField's willChangeValueForKey_("stringValue")
    assignedFileNameSearchField's setStringValue_(filename of fr)
    assignedFileNameSearchField's didChangeValueForKey_("stringValue")
end assignedFileNamesDblClickEntry_

FYI,
logged value of fr was:
{
FileName = “(CS)Bead - B4 5-8in.eps”;
portfolioID = 60671;
sqid = 46359;
}

assignedFileNameSearchField’s displayed value correctly changed to “(CS)Bead - B4 5-8in.eps”

However, the Scroll View did not re-filter until I manually made a text modification to the field.

OK, it looks like you will have to set the predicate of the array controller directly. Assuming theArrayController is an outlet to the array controller, something like:

 searchField's setStringValue_(filename of fr)
 set thePred to current application's NSPredicate's predicateWithFormat_("FileName contains [cd] %@", filename of fr)
 theArrayController's setFilterPredicate_(thePred)

Bingo!!!

I had a feeling I was going to have to go that route, but I figured I would try to see if I could make the notification method work first.

With the foundation of your book, along with the Xcode doumentation, a few reliable online resources, occassionally clarified by your help on this forum, I am learning a lot this year!

Thank you again!

Now I have a follow up question.

The filter predicate is properly filtering the list, showing all current “FileName” rows which “Contains” the Search Field’s string value.

I am using “Contains” so the user can see similar file names as they type.

However, I don’t want the user to be able to “Assign” an new file name if there is an en exact [case insensitive] MATCH in the current arranged and filtered objects. Specifically, as mentioned in the first post, If there is a MATCH in the currently filtered data, I want to set the visibility of a warning image and the enabled of a button to “Off” (this is currently working, but it is tied to the Count of assignedFileNamesArrayController’s arranged objects.

I figured I could do the same thing by comparing to a duplicate array controller, with the distinction of having its predicate set to (“FileName matches [cd]%@”,fName).

Here is the code I am using to set the predicate for each ArrayController:
set thePred to current application’s NSPredicate’s predicateWithFormat_(“FileName contains [cd]%@”,fName)
assignedFileNamesArrayController’s setFilterPredicate_(thePred)
set thePred to current application’s NSPredicate’s predicateWithFormat_(“FileName matches [cd]%@”,fName)
assignedFileNamesDuplicateArrayController’s setFilterPredicate_(thePred)

The problem is, the current functionality relies upon the SearchField using assignedFileNamesArrayController as its delegate, which enables the arraycontroller to filter as the user types.

I can’t assign the same SearchField to be the delegate of assignedFileNamesDuplicateArrayController, so how do I dynamically update its arrangedObjects?

Too complicated to follow?

Another thought…

Could I create a new ArrayController, binding its controller content to assignedFileNamesArrayController’s arrangedObjects, and then set the filter predicate of this new controller “assignedFileNamesArrayControllerDupe” to find exact MATCHES of the currently entered Search Field content.

Then I could bind the visibility and enabled to the COUNT of “assignedFileNamesArrayControllerDupe”

i.e.

 set thePred to current application's NSPredicate's predicateWithFormat_("FileName matches [c]%@",fName)
 assignedFileNamesTestArrayController's setFilterPredicate_(thePred)

I tried it, even creating an NSView to display the contents of assignedFileNamesArrayControllerDupe’s arrangedObjects, but it seems to ignore the above predicate, only showing a duplicate of the assignedFileNamesArrayController’s NSView.

There must be an easier way of doing this that I simply don’t know about.

I think I follow…

I don’t think an extra binding is the answer. You’ll probably need to use a delegate method like controlTextDidChange_, and in that get the array controller’s selectedObjects(), call filteredArrayUsingPredicate_() with the new predicate on the result, and act according to whether you end up with an empty list.

And your predicate should use ==, not matches. You use matches for regular expression matching.

This may be a stupid question, but I created the controlTextDidChange_ method, but it never gets called.

The user is typing into a search field. I want it to evaluate constantly as the user types or otherwise edits the search field.

Did you connect the delegate of the text field to the class where the method is implemented in Interface Builder?

Of course not!

(thanks):confused:

Hi,

I have the same issue ; I created the following lines in the applescript :

on controlTextDidChange_(aNotification)        
        log("something")
    end controlTextDidChange_

I have a textfield in my main window.

I don’t master the terminology enough to understand how to “connect the delegate of the text field to the class where the method is implemented in Interface Builder”.

I am using Mavericks and xCode 5.1.1

Thanks in advance for any help,
Nicolas

In the interface, control-click on the text field and a window will appear. Click and drag from the circle next to where it says delegate under the Outlets heading, and drag across to the icon at the left that represents the class you want to be the delegate; when on top of it, release the mouse button.

¢ In the side bar, select the .xib file
¢ select the text field
¢ Press ⌥⌘6 to show the Connection Inspector
¢ In the Outlets section, put the mouse over the circle in the delegate line and control-drag to the blue cube on the left side which represents the target class

Thanks to both of you.

I assumed the “target class” / “class I wanted to be the delegate” what the blue cube “App Delegate” and it works.

This will allow me to show in real time time the number of characters entered by the user.

I tried an additional binding with “sent actions” and it still works !

Nicolas