Fix Populated NSMenu Of Files, Folders And Their Respected Images
-
hi.
i've been on this task for almost a week, and i still can't get it
right. basically, i would like to have an NSMenu populated with all
the files and folders of a specific directory. for this example i'll
use ~/Documents. the code below only partially works. it will list
files and folders from Documents in an NSMenu, but they are not
selectable. i've added a @selector, but it doesn't seem to be called.
the selector if just an example method - i don't want to really
terminate the app when an item is selected, i simply want the item to
launch.
second, it would be ideal to have the folders also produce their own
NSMenu list of files contained in them - i have no idea how to do
this.
third, the code below codes the NSMenuItem to be titled "Documents",
but it's title is not displayed when it's inserted at index:1 of
NSMenu *theMenu. however, if i insert it into [NSApp mainMenu], the
title "Documents" will display. this doesn't make sense to me.
and finally, i would love to have each of the files and folders to be
added to the NSMenu with their respected icons. my attempts to do
this have failed because i do not know how to get the path of each
file or folder that is being enumerated. the code below will warn
that NSString does not respond to Path.
to me this whole thing seems like something very common, and would be
used a lot by developers, but i've had such difficulty trying to find
resources. i've found bits and pieces and lots of dead ends. please
someone help me with this. sample code would be amazing... AMAZING!
or at least a guide into the right direction.
thanks in advance :)
-=-=-=- CODE -=-=-=-
- (void)awakeFromNib
{
NSMenu *documentsMenu = [[NSMenu alloc] initWithTitle:@"Documents"];
NSMenuItem *documentsItem = [[NSMenuItem alloc] initWithTitle: @""
action: nil keyEquivalent: @""];
[documentsItem setSubmenu:documentsMenu];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsDirectory = [@"~/Desktop" stringByExpandingTildeInPath];
NSDirectoryEnumerator *directoryEnumerator = [fileManager
enumeratorAtPath:documentsDirectory];
NSString *fileOrFolder;
while ((fileOrFolder = [directoryEnumerator nextObject]))
{
//ignore invisible files
if ([fileOrFolder hasPrefix:@"."])
{
continue;
}
NSLog(fileOrFolder);
NSMenuItem *documentsItem = [[NSMenuItem alloc]
initWithTitle:fileOrFolder action:@selector(launchFileOrFolder:)
keyEquivalent:@""];
NSDictionary *fileAttributes = [fileManager
fileAttributesAtPath:documentsDirectory traverseLink:NO];
if ([[fileAttributes fileType] isEqualToString:NSFileTypeDirectory])
{
[directoryEnumerator skipDescendents];
}
[documentsItem setImage:[[NSWorkspace sharedWorkspace]
iconForFile:[documentsItem path]]];
[documentsMenu addItem:documentsItem];
[documentsItem release];
}
//"theMenu" is an IBOutlet to an NSMenu with 2 items already listed.
i place documentsItem between those 2 items at index:1.
[theMenu insertItem:documentsItem atIndex:1];
//[[NSApp mainMenu] insertItem:documentsItem atIndex:1];
[documentsMenu release];
[documentsItem release];
}
- (void)launchFileOrFolder
{
[NSApp terminate];
}
-=-=-=- END CODE -=-=-=- -
On Dec 5, 2008, at 9:44 AM, Chunk 1978 wrote:> hi.
Hi.> i've been on this task for almost a week, and i still can't get it
> right. basically, i would like to have an NSMenu populated with all
> the files and folders of a specific directory. for this example i'll
> use ~/Documents. the code below only partially works. it will list
> files and folders from Documents in an NSMenu, but they are not
> selectable. i've added a @selector, but it doesn't seem to be called.
> the selector if just an example method - i don't want to really
> terminate the app when an item is selected, i simply want the item to
> launch.
You have to also call setTarget: on the menu items so it knows which
object to send the message to. In your case you'd probably pass self
as the object. Also if you want to access the path again during your
selector it would probably be easiest to set the path for the item as
the representedObject.
NSMenuItem *item = /* your item with @selector */
[item setTarget:self];
[item setRepresentedObject:[documentsDirectory
stringByAppendingPathComponent:fileOrFolder]];
Then in your method:
- (void)actionMethod:(id)sender {
id fullPath = [sender representedObject];
/* do something with fullPath */
}> second, it would be ideal to have the folders also produce their own
> NSMenu list of files contained in them - i have no idea how to do
> this.
You'll have to do some refactoring to accomplish this. Essentially,
break apart your method into one that creates a menu for a directory's
items and returns the resulting menu. That method will call itself to
create menus for subfolders which you would add as subitems to your
menu. You would then just call that method on your root directory,
Documents in your case, and add the resulting tree of menus wherever
you're interested in.> third, the code below codes the NSMenuItem to be titled "Documents",
> but it's title is not displayed when it's inserted at index:1 of
> NSMenu *theMenu. however, if i insert it into [NSApp mainMenu], the
> title "Documents" will display. this doesn't make sense to me.
I believe this is a consequence of how you're setting the title and
where you're adding the menu. If you set the title on the
documentsItem as well as the documentsMenu it should appear regardless
of where you attach the menu.> and finally, i would love to have each of the files and folders to be
> added to the NSMenu with their respected icons. my attempts to do
> this have failed because i do not know how to get the path of each
> file or folder that is being enumerated. the code below will warn
> that NSString does not respond to Path.
You can get the icon for the path with this:
[[NSWorkspace sharedWorkspace] iconForFile:[documentsDirectory
stringByAppendingPathComponent:fileOrFolder]];
Ashley -
thanks ashley, you cleared up a lot for me. however, i'm now presented
with two (seemingly) small issues. the first is determining whether
the directory is empty. i've added an array with
directoryContentsAtPath, and an if statement counting the array, but
it doesn't seem to work.
second, how is it possible to change the size of the iconForFile(s)
using setSize:NSMakeSize(16, 16), or any other way?
my updated code follows:
-=-=-=-=-
- (void)awakeFromNib
{
NSMenu *desktopMenu = [[NSMenu alloc] initWithTitle:@""];
NSMenuItem *desktopItem = [[NSMenuItem alloc] initWithTitle:@"Desktop
Files" action:nil keyEquivalent:@""];
[desktopItem setSubmenu:desktopMenu];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *desktopDirectory = [@"~/Desktop/9" stringByExpandingTildeInPath];
NSDirectoryEnumerator *directoryEnumerator = [fileManager
enumeratorAtPath:desktopDirectory];
NSString *fileOrFolder;
NSArray *theFolderContents = [fileManager
directoryContentsAtPath:desktopDirectory];
if ([theFolderContents count] == 0)
{
NSLog(@"no files");
NSMenuItem *noFilesItem = [[NSMenuItem alloc] initWithTitle:@"No
Files" action:nil keyEquivalent:@""];
[desktopMenu addItem:noFilesItem];
[noFilesItem release];
}
else
{
while ((fileOrFolder = [directoryEnumerator nextObject]))
{
//ignore invisible files
if ([fileOrFolder hasPrefix:@"."])
{
continue;
}
[directoryEnumerator skipDescendents];
NSMenuItem *desktopItems = [[NSMenuItem alloc]
initWithTitle:fileOrFolder action:@selector(launchFileOrFolder:)
keyEquivalent:@""];
[desktopItems setTarget:self];
[desktopItems setRepresentedObject:[desktopDirectory
stringByAppendingPathComponent:fileOrFolder]];
[desktopItems setImage:[[NSWorkspace sharedWorkspace]
iconForFile:[desktopDirectory
stringByAppendingPathComponent:fileOrFolder]]];
[desktopMenu addItem:desktopItems];
[desktopItems release];
}
}
[theMenu insertItem:desktopItem atIndex:1];
[desktopMenu release];
[desktopItem release];
}
- (void)launchFileOrFolder:(id)sender
{
NSString *filePath = [sender representedObject];
[[NSWorkspace sharedWorkspace] openFile:filePath];
}
- (void)dealloc
{
[super dealloc];
}
-=-=-=-=-
On Fri, Dec 5, 2008 at 3:07 PM, Ashley Clark <aclark...> wrote:> On Dec 5, 2008, at 9:44 AM, Chunk 1978 wrote:
>
>> hi.
>
> Hi.
>
>> i've been on this task for almost a week, and i still can't get it
>> right. basically, i would like to have an NSMenu populated with all
>> the files and folders of a specific directory. for this example i'll
>> use ~/Documents. the code below only partially works. it will list
>> files and folders from Documents in an NSMenu, but they are not
>> selectable. i've added a @selector, but it doesn't seem to be called.
>> the selector if just an example method - i don't want to really
>> terminate the app when an item is selected, i simply want the item to
>> launch.
>
> You have to also call setTarget: on the menu items so it knows which object
> to send the message to. In your case you'd probably pass self as the object.
> Also if you want to access the path again during your selector it would
> probably be easiest to set the path for the item as the representedObject.
>
> NSMenuItem *item = /* your item with @selector */
> [item setTarget:self];
> [item setRepresentedObject:[documentsDirectory
> stringByAppendingPathComponent:fileOrFolder]];
>
> Then in your method:
>
> - (void)actionMethod:(id)sender {
> id fullPath = [sender representedObject];
>
> /* do something with fullPath */
> }
>
>> second, it would be ideal to have the folders also produce their own
>> NSMenu list of files contained in them - i have no idea how to do
>> this.
>
> You'll have to do some refactoring to accomplish this. Essentially, break
> apart your method into one that creates a menu for a directory's items and
> returns the resulting menu. That method will call itself to create menus for
> subfolders which you would add as subitems to your menu. You would then just
> call that method on your root directory, Documents in your case, and add the
> resulting tree of menus wherever you're interested in.
>
>> third, the code below codes the NSMenuItem to be titled "Documents",
>> but it's title is not displayed when it's inserted at index:1 of
>> NSMenu *theMenu. however, if i insert it into [NSApp mainMenu], the
>> title "Documents" will display. this doesn't make sense to me.
>
> I believe this is a consequence of how you're setting the title and where
> you're adding the menu. If you set the title on the documentsItem as well as
> the documentsMenu it should appear regardless of where you attach the menu.
>
>> and finally, i would love to have each of the files and folders to be
>> added to the NSMenu with their respected icons. my attempts to do
>> this have failed because i do not know how to get the path of each
>> file or folder that is being enumerated. the code below will warn
>> that NSString does not respond to Path.
>
> You can get the icon for the path with this:
>
> [[NSWorkspace sharedWorkspace] iconForFile:[documentsDirectory
> stringByAppendingPathComponent:fileOrFolder]];
>
>
> Ashley
>
> -
nevermind, i managed to get it right... not sure how efficient this
code is, but at least it works :)
-=-=-=-=-
@interface AppController : NSObject
{
IBOutlet NSMenu *theMenu;
}
- (void)launchFileOrFolder:(id)sender;
@end
-=-=-=-=-=-
#import "AppController.h"
@implementation AppController
- (void)awakeFromNib
{
NSMenu *desktopMenu = [[NSMenu alloc] initWithTitle:@""];
NSMenuItem *desktopItem = [[NSMenuItem alloc] initWithTitle:@"Desktop
Files" action:nil keyEquivalent:@""];
[desktopItem setSubmenu:desktopMenu];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *desktopDirectory = [@"~/Desktop" stringByExpandingTildeInPath];
NSDirectoryEnumerator *directoryCount = [fileManager
enumeratorAtPath:desktopDirectory];
NSDirectoryEnumerator *directoryEnumerator = [fileManager
enumeratorAtPath:desktopDirectory];
NSString *fileOrFolder;
int hiddenFIles = 0;
while ((fileOrFolder = [directoryCount nextObject]))
{
if ([fileOrFolder hasPrefix:@"."])
{
hiddenFIles++;
}
}
NSLog(@"hiddenfiles = %d", hiddenFIles);
NSArray *directoryContents = [fileManager
directoryContentsAtPath:desktopDirectory];
int allFiles = [directoryContents count];
NSLog(@"totalfiles = %d", allFiles);
if ((allFiles - hiddenFIles) == 0)
{
NSLog(@"directory contains only hidden files");
NSMenuItem *noFilesItem = [[NSMenuItem alloc] initWithTitle:@"Empty"
action:nil keyEquivalent:@""];
[desktopMenu addItem:noFilesItem];
[noFilesItem release];
//or alternatively just disable the item
//with this line of code: [desktopItem setEnabled:NO];
}
else
{
while ((fileOrFolder = [directoryEnumerator nextObject]))
{
//ignore invisible files
if ([fileOrFolder hasPrefix:@"."])
{
continue;
}
[directoryEnumerator skipDescendents];
NSMenuItem *desktopItems = [[NSMenuItem alloc]
initWithTitle:fileOrFolder action:@selector(launchFileOrFolder:)
keyEquivalent:@""];
[desktopItems setTarget:self];
[desktopItems setRepresentedObject:[desktopDirectory
stringByAppendingPathComponent:fileOrFolder]];
NSImage *fileOrFolderIcons = [[NSWorkspace sharedWorkspace]
iconForFile:[desktopDirectory
stringByAppendingPathComponent:fileOrFolder]];
[fileOrFolderIcons setScalesWhenResized:YES];
NSSize mySize; mySize.width=16; mySize.height=16;
[fileOrFolderIcons setSize:mySize];
[desktopItems setImage:fileOrFolderIcons];
[desktopMenu addItem:desktopItems];
[desktopItems release];
}
}
[theMenu insertItem:desktopItem atIndex:1];
[desktopMenu release];
[desktopItem release];
}
- (void)launchFileOrFolder:(id)sender
{
NSString *filePath = [sender representedObject];
[[NSWorkspace sharedWorkspace] openFile:filePath];
}
- (void)dealloc
{
[super dealloc];
}
@end
-=-=-=-=-
On Sat, Dec 6, 2008 at 6:01 AM, Chunk 1978 <chunk1978...> wrote:> thanks ashley, you cleared up a lot for me. however, i'm now presented
> with two (seemingly) small issues. the first is determining whether
> the directory is empty. i've added an array with
> directoryContentsAtPath, and an if statement counting the array, but
> it doesn't seem to work.
>
> second, how is it possible to change the size of the iconForFile(s)
> using setSize:NSMakeSize(16, 16), or any other way?
>
> my updated code follows:
>
> -=-=-=-=-
>
> - (void)awakeFromNib
> {
> NSMenu *desktopMenu = [[NSMenu alloc] initWithTitle:@""];
> NSMenuItem *desktopItem = [[NSMenuItem alloc] initWithTitle:@"Desktop
> Files" action:nil keyEquivalent:@""];
> [desktopItem setSubmenu:desktopMenu];
>
> NSFileManager *fileManager = [NSFileManager defaultManager];
> NSString *desktopDirectory = [@"~/Desktop/9" stringByExpandingTildeInPath];
> NSDirectoryEnumerator *directoryEnumerator = [fileManager
> enumeratorAtPath:desktopDirectory];
> NSString *fileOrFolder;
> NSArray *theFolderContents = [fileManager
> directoryContentsAtPath:desktopDirectory];
>
> if ([theFolderContents count] == 0)
> {
> NSLog(@"no files");
> NSMenuItem *noFilesItem = [[NSMenuItem alloc] initWithTitle:@"No
> Files" action:nil keyEquivalent:@""];
> [desktopMenu addItem:noFilesItem];
> [noFilesItem release];
> }
> else
> {
> while ((fileOrFolder = [directoryEnumerator nextObject]))
> {
> //ignore invisible files
> if ([fileOrFolder hasPrefix:@"."])
> {
> continue;
> }
>
> [directoryEnumerator skipDescendents];
>
> NSMenuItem *desktopItems = [[NSMenuItem alloc]
> initWithTitle:fileOrFolder action:@selector(launchFileOrFolder:)
> keyEquivalent:@""];
> [desktopItems setTarget:self];
> [desktopItems setRepresentedObject:[desktopDirectory
> stringByAppendingPathComponent:fileOrFolder]];
>
> [desktopItems setImage:[[NSWorkspace sharedWorkspace]
> iconForFile:[desktopDirectory
> stringByAppendingPathComponent:fileOrFolder]]];
>
> [desktopMenu addItem:desktopItems];
> [desktopItems release];
> }
> }
>
> [theMenu insertItem:desktopItem atIndex:1];
> [desktopMenu release];
> [desktopItem release];
> }
>
> - (void)launchFileOrFolder:(id)sender
> {
> NSString *filePath = [sender representedObject];
> [[NSWorkspace sharedWorkspace] openFile:filePath];
> }
>
> - (void)dealloc
> {
> [super dealloc];
> }
>
> -=-=-=-=-
>
>
>
>
>
>
>
>
>
> On Fri, Dec 5, 2008 at 3:07 PM, Ashley Clark <aclark...> wrote:
>> On Dec 5, 2008, at 9:44 AM, Chunk 1978 wrote:
>>
>>> hi.
>>
>> Hi.
>>
>>> i've been on this task for almost a week, and i still can't get it
>>> right. basically, i would like to have an NSMenu populated with all
>>> the files and folders of a specific directory. for this example i'll
>>> use ~/Documents. the code below only partially works. it will list
>>> files and folders from Documents in an NSMenu, but they are not
>>> selectable. i've added a @selector, but it doesn't seem to be called.
>>> the selector if just an example method - i don't want to really
>>> terminate the app when an item is selected, i simply want the item to
>>> launch.
>>
>> You have to also call setTarget: on the menu items so it knows which object
>> to send the message to. In your case you'd probably pass self as the object.
>> Also if you want to access the path again during your selector it would
>> probably be easiest to set the path for the item as the representedObject.
>>
>> NSMenuItem *item = /* your item with @selector */
>> [item setTarget:self];
>> [item setRepresentedObject:[documentsDirectory
>> stringByAppendingPathComponent:fileOrFolder]];
>>
>> Then in your method:
>>
>> - (void)actionMethod:(id)sender {
>> id fullPath = [sender representedObject];
>>
>> /* do something with fullPath */
>> }
>>
>>> second, it would be ideal to have the folders also produce their own
>>> NSMenu list of files contained in them - i have no idea how to do
>>> this.
>>
>> You'll have to do some refactoring to accomplish this. Essentially, break
>> apart your method into one that creates a menu for a directory's items and
>> returns the resulting menu. That method will call itself to create menus for
>> subfolders which you would add as subitems to your menu. You would then just
>> call that method on your root directory, Documents in your case, and add the
>> resulting tree of menus wherever you're interested in.
>>
>>> third, the code below codes the NSMenuItem to be titled "Documents",
>>> but it's title is not displayed when it's inserted at index:1 of
>>> NSMenu *theMenu. however, if i insert it into [NSApp mainMenu], the
>>> title "Documents" will display. this doesn't make sense to me.
>>
>> I believe this is a consequence of how you're setting the title and where
>> you're adding the menu. If you set the title on the documentsItem as well as
>> the documentsMenu it should appear regardless of where you attach the menu.
>>
>>> and finally, i would love to have each of the files and folders to be
>>> added to the NSMenu with their respected icons. my attempts to do
>>> this have failed because i do not know how to get the path of each
>>> file or folder that is being enumerated. the code below will warn
>>> that NSString does not respond to Path.
>>
>> You can get the icon for the path with this:
>>
>> [[NSWorkspace sharedWorkspace] iconForFile:[documentsDirectory
>> stringByAppendingPathComponent:fileOrFolder]];
>>
>>
>> Ashley
>>
>>
>


