Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > NSPopUpButton & file handling?

NSPopUpButton & file handling?
Thread Tools
dws
Forum Regular
Join Date: Apr 2001
Location: Minneapolis, MN, USA
Status: Offline
Reply With Quote
May 4, 2001, 03:40 AM
 
I've worked on the following issue for a number of days and must be missing something fundamental, because I'm not getting very far. I'm a Cocoa newbie and am still wrestling with the whole concept of Objective-C... I hope that you can help me.

I'm probably reaching a little beyond my skills... but I would like to place all the file names in a particular folder in an NSArray (or NSMutableArray); which could be accessed by my program in a pull-down menu, where clicking on one of the names would result in another window being opened containing the chosen file (all the files are created by this program). Ideally, I'd like the pull-down menu to dynamically update itself if new files are added to or deleted from the folder. At this point, I'd be thrilled if I could get the file list to simply display in the pull-down menu!

I don't think that IB is a problem (subclass creation, connections, adding the files to PB, etc.)(though I could be wrong!). The real problem is trying to figure out which NS... to use and how to use it/them/whatever!

I've looked at the documentation and tried dozens of variations, but am not having success. I'm afraid that in trying to deal with NSFileManager (to get the file list), NSArray (to hold the list), NSPopUpButton (title & file names?) I'm getting so confused that I'm no longer sure what I'm doing. In fact, the situation is so bad I'm embarrassed to even show code fragments:

// in document.h implementation
IBOutlet NSPopUpButton *folderContents;

// in document.m
- (IBAction)getFilenames id)sender
{
NSArray *filesArray = [[NSArray alloc] initWithArray:[[NSFileManager defaultManager] directoryContentsAtPath:@"/Users/userid/Documents/Foldername"]];
[folderContents removeAllItems];
[folderContents addItemsWithTitles:filesArray];
[filesArray dealloc];
}

I suppose that I'm using the guess-and-try-it method of programming, where I measure success by what kind of response I get from the code. In this case, however, nothing happens (other than the code compiling correctly); so I'm at a loss.

Any help that you folks could give me would be greatly appreciated.
     
tie
Professional Poster
Join Date: Feb 2001
Status: Offline
Reply With Quote
May 4, 2001, 05:22 PM
 
Well, I hope you don't mind but I just shamelessly copied your code, pasted it into one of my projects, and ran it. And it works fine.

Here's a sketch of the basic code:
Code:
{ NSMenu *newMenu; NSMenuItem *newItem; NSString *path; NSEnumerator *enumer = [[[NSFileManager defaultManager] directoryContentsAtPath:@"/Users/breic/Documents/"] objectEnumerator]; newMenu = [[NSMenu alloc] initWithTitle:@"FinderDockling"]; while (path = [enumer nextObject]) { newItem = [[NSMenuItem alloc] initWithTitle ath action:@selector(openItem) keyEquivalent:@""]; [newItem setTarget:self]; [newMenu addItem:newItem]; [newItem release]; } }
Are you sure the action is being called?

[This message has been edited by tie (edited 05-04-2001).]
The 4 o'clock train will be a bus.
It will depart at 20 minutes to 5.
     
dws  (op)
Forum Regular
Join Date: Apr 2001
Location: Minneapolis, MN, USA
Status: Offline
Reply With Quote
May 4, 2001, 11:57 PM
 
Thanks tie...

The method you presented is quite clear. Nice; though I had thought that you could simply pass a pull-down menu an array, without having to load each element.

I just as shamelessly copied (and retrofitted) your code and tried it out. Compiles beautifully. Still doesn't work! The action isn't being called. I tried a number of approaches, but nothing works. I'm clearly not understanding something fairly fundamental. This whole Object-oriented thing just isn't clicking with me yet. I suppose that I learned how to program too many years ago and keep expecting to manipulate data, rather than calling classes to do it for me!

I thought that I understood the concept of creating subclasses, outlets & actions, and connecting it all together. Apparently not!

Oh well... It looks like I'm going to have to be patient and wait for the upcoming O'Reilly book on Cocoa programming. Hopefully it will contain tutorials that will better explain how to implement some common techniques (the excerpts on their website look promising). Being taught by Apple to say Hello & to convert currency doesn't go very far in developing a basic understanding of implementing classes in realworld programs. Apple's documentation is fine, but doesn't really get into how to put it all together - too little detail or too much! The scant Cocoa source code available on the net tends to be so complicated it's easy to get lost. The only 'current' resource for tutorials I've found on the net is CocoaDevCentral (I can make sheets do their thing, but not arrays!).

I read today that O'Reilly will be giving copies of their new books away as gifts at WWDC, so I hope that my copy will arrive by the end of this month. The new iBook might be on my wish list, but I need THAT book!!!
     
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
May 5, 2001, 04:14 AM
 
The code as originally posted should work, provided the outlets and actions are set up correctly. I take it you have a button in the UI, and when you press it the popup list should fill correctly? If so, make sure you've set the action on the button to call the getFilenames: method.

Make sure you've assigned the folderContents outlet to the popup button. If it's not set, then it's a nil variable, and the effect of the code will be to do nothing.

You main want to have the trailing "/" on the pathname... I forget if it makes a difference with that particular NSFileManager method, but it may.

Couple of minor nits -- you should never call -dealloc directly on an object; it will get called automatically when the retain count reaches zero. Call -release instead -- that offsets the retain represented by the +alloc call.

In the same area, the directoryContentsAtPath: method already returns an autoreleased NSArray instance, so there's no need to allocate another NSArray instance as a copy -- you can just use the original return value. You would then not need the -release call either :-)

You don't need to explicitly set the action on each individual item, though you can. When an item is chosen in a popup, the item's target/action is used if it's set, otherwise the NSPopUpButton's target/action is used.

In tie's code, the action should be @selector(openItem (i.e. with the ":", signifying an argument), since action methods should take one argument (the "sender"). It will work if you use a method that doesn't take any arguments, but it's not the best form :-)
     
dws  (op)
Forum Regular
Join Date: Apr 2001
Location: Minneapolis, MN, USA
Status: Offline
Reply With Quote
May 5, 2001, 01:56 PM
 
Success!

As is typical when programming, a simple error leads to hours of frustration. Encouraged by being told that my original code should work (with slight modifications), I redid the IB connections and I finally have a pull-down menu that lists the contents of a folder! Yeah!!

Thank you, lindberg, for cluing me in to the fact that the directoryContentsAtPath: method automatically passes an array. I must have missed that in the documentation.

I also tried tie's code, but couldn't get it to work. Oh well, I'll leave that for another day!

Now... On to the next problem (Isn't there always a next problem!?!)...

I now have a pull-down menu that displays the contents of a folder. Except that it does more than I want! The Title (0th element) displays as ".DS_Store", the 1st element is ".FBCIndex", the 2nd element is ".FBCLockFolder". The rest of the elements are the contents of the folder. So now I get to plumb the depths of Unix file structures! Oh goody!! [Yes, I do say, 'Oh goody' when I'm speaking - on rare occasions - but I try to grunt and scratch my balls afterward (balance, you know)!]

I could certainly slog through each element of a folder, test to make sure that its suffix is equal to the file types that my program wants to see, or test each element and reject anything that starts with a "."; but I had been hoping to not have to assign each element at all! Does anyone know a way to perform the original code, but to tell it: "Hey, if Finder doesn't want to see it, neither do I!"; all without resorting to testing each element?

As always, I'm eternally grateful for any assistance you folks might be able to offer.

     
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
May 5, 2001, 07:07 PM
 
By Unix convention, any file that starts with "." is not displayed with the "ls" command (unless the -a flag is given), and is therefore kind of "hidden". Finder follows the same convention, with the addition that any file listed in a file called ".hidden" is also not displayed. I don't know of any API that actually does this, though it's not hard to write.

The easiest way would just be to filter out paths that start with ".". It's pretty easy code.

If you want just the files that have a particular extension, that's possible too, and just as easy. You can do it manually, or there is a path-completion method on NSString declared in NSPathUtilities.h that can filter by types. The method tries to do way too much, but it's very useful. I typically write cover methods that use it for cleaner usage. [The NSString method predated NSFileManager, which is why it exists in the first place.]

You could try using something like (just typed in, not tested):

Code:
@interface NSFileManager (MyAdditions) - (NSArray *)directoryContentsAtPath:(NSString *)path filterTypes:(NSArray *)filterTypes; @end @implementation NSFileManager (MyAdditions) - (NSArray *)directoryContentsAtPath:(NSString *)path filterTypes:(NSArray *)filterTypes { NSArray *files = nil; if (![path hasSuffix:@"/"]) path = [path stringByAppendingString:@"/"]; [path completePathIntoString:NULL caseSensitive:NO matchesIntoArray:&files filterTypes:filterTypes]; return files; } @end

Then you could pass in an array of file extensions to filter by.


[This message has been edited by lindberg (edited 05-05-2001).]
     
dws  (op)
Forum Regular
Join Date: Apr 2001
Location: Minneapolis, MN, USA
Status: Offline
Reply With Quote
May 5, 2001, 10:23 PM
 
Thanks lindberg...

Your little addition is wonderful. I've copied it and put it in a special place; for use when my code starts getting a little more complicated than 'See Spot run!'

I gave up (temporarily) on my idea of a simple approach; and now check each element for 'appropriateness' prior to allowing it into the pull-down menu. It works beautifully.

If I hadn't started out making a stupid connections mistake, I probably would have never started this thread. But... I'm glad that I did. Several valuable concepts were covered. Things that will benefit lots of people who are just starting out with Cocoa. Once the books start coming out, newbies won't have to bumble around in the dark - but that hasn't happened yet. The assistance of good folks like tie and linberg benefit all Cocoa newbies! Thanks.
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 09:56 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2