Skip to content

Instantly share code, notes, and snippets.

@BlackFrog1
Created March 24, 2011 03:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BlackFrog1/884478 to your computer and use it in GitHub Desktop.
Save BlackFrog1/884478 to your computer and use it in GitHub Desktop.
//
// LoginItem.h
// Medium
//
// Created by Collin Bennett on 1/13/11.
// Copyright 2011 Black Frog. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface LoginItem : NSObject <NSCoding> {
@private
NSURL *url_;
// ivars based on url
BOOL isFile_;
NSString *name_;
NSString *kind_;
// keep track if the changes need to be saved
BOOL dirty_;
// user control ivars
BOOL hide_;
BOOL notify_;
NSUInteger seconds_;
}
@property (nonatomic, readonly, retain) NSString *name;
@property (nonatomic, readonly, retain) NSString *kind;
@property (readonly, getter=isDirty) BOOL dirty;
@property (nonatomic, assign) BOOL hide;
@property (nonatomic, assign) BOOL notifyLaunch;
@property (nonatomic, assign) NSUInteger launchSeconds;
- (id)initWithPath:(NSString *)path;
- (id)copyWithZone:(NSZone *)zone;
- (NSImage *)image;
- (NSString *)toolTip;
@end
//
// LoginItem.m
// Medium
//
// Created by Collin Bennett on 1/13/11.
// Copyright 2011 Black Frog. All rights reserved.
//
#import "LoginItem.h"
// for debugging
//#define LOG_URL
//#define DEBUG
@interface LoginItem ()
// This second declaration of the dirty property
// automatically creates the KVO notification
// when setDirty is called
@property (readwrite, getter=isDirty) BOOL dirty;
- (NSImage *)createIconImage:(OSType)code;
- (void)debugURL;
@end
@implementation LoginItem
@synthesize name = name_;
@synthesize kind = kind_;
@synthesize dirty = dirty_;
@synthesize hide = hide_;
@synthesize notifyLaunch = notify_;
@synthesize launchSeconds = seconds_;
- (NSImage *)createIconImage:(OSType)code {
// TODO: Research on internet the kGenericWORMIcon,
// because on my computer the worm icon is blank, just wondering if that is correct
NSImage *img = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(code)];
//[img setSize:NSMakeSize(ICON_SIZE, ICON_SIZE)];
return img;
// kGenericURLIcon
// kInternetLocationGenericIcon
// This sample code use the TIFFRepresentation
// I should look into using it also
// NSWorkspace *wksp = [NSWorkspace sharedWorkspace];
// timeMachineIconData = [[[wksp iconForFile:[wksp absolutePathForAppBundleWithIdentifier:@"com.apple.backup.launcher"]] TIFFRepresentation] retain];
}
- (void)debugURL {
#ifdef LOG_URL
NSLog(@"Scheme: %@", [url_ scheme]);
NSLog(@"URL Absolute: %@", [url_ absoluteString]);
NSLog(@"File Path URL: %@", [[url_ filePathURL] absoluteString]);
NSLog(@"File Reference URL: %@", [[url_ fileReferenceURL] absoluteString]);
#endif
}
- (id)initWithPath:(NSString *)path {
if ((self = [super init]) != nil) {
// Check if our path starts with a tilde
if ([path hasPrefix:@"~"])
path = [path stringByExpandingTildeInPath];
// I could create all the NSURL with +URLWithString using a valid system path file
// but the when I try to retrieve the Kind String using LSCopyKindStringForURL
// I get the following error: [paramErr] (error in user parameter list)
if ([path hasPrefix:@"/"]) // indicate we have a system path
url_ = [NSURL fileURLWithPath:path];
else // everything else must conform to RFC 2396
url_ = [NSURL URLWithString:path];
// Malformed path will result in a nil NSURL
if (url_ == nil) {
NSLog(@"Malformed Path: %@", path);
[self release];
return nil;
}
// we are going to need the url object around for awhile
[url_ retain];
// Check the scheme of the url
NSString *itemScheme = [url_ scheme];
// perform a case insensitive match because the user
// could type in all caps, AARG
if (!([itemScheme caseInsensitiveCompare:@"file"] != NSOrderedSame))
isFile_ = YES;
if (!isFile_) {
name_ = path;
// We have a non-file based url scheme
// get the application that can handle this scheme
// and set the kind string to the application display name
CFURLRef appURL = nil;
LSGetApplicationForURL((CFURLRef)url_, kLSRolesAll, NULL,
&appURL);
if (appURL != nil) {
// get display name for kind
CFStringRef displayName = nil;
LSCopyDisplayNameForURL(appURL, &displayName);
if (displayName != nil)
kind_ = (NSString *)displayName;
// TODO: Research kLSRequestIconAndKind for LSCopyItemInfoForURL
// According to the doc, it's not used.
// find what really means????
CFRelease(appURL);
}
} else {
// Create a local file manager because this is consider thread-safe
NSFileManager *localFileManager = [[NSFileManager alloc] init];
// url is file-based, use it's display name
name_ = [localFileManager displayNameAtPath:[url_ path]];
if ([localFileManager fileExistsAtPath:[url_ path]]) {
// kind string
CFStringRef kindStr = nil;
OSStatus stat = LSCopyKindStringForURL((CFURLRef)url_, &kindStr);
if (kindStr != nil) {
kind_ = (NSString*)kindStr;
} else {
NSLog(@"Kind String Status: %d", stat);
// TODO: Why is Launch Services returning "File Manager Result Codes?"
// TODO: -43 [fnfErr] (File not found)
// The documents doesn't match the OSStatus
}
}
[localFileManager release];
}
[name_ retain];
// all newly created item are dirty
dirty_ = YES;
#ifdef DEBUG
NSLog(@"-------------------------------------------------------");
NSLog(@"Path: %@", path);
[self debugURL];
#endif
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
LoginItem *newObj = [[[self class] alloc] init];
newObj->url_ = [url_ retain];
newObj->name_ = [name_ retain];
newObj->kind_ = [kind_ retain];
newObj->isFile_ = isFile_;
newObj->hide_ = hide_;
newObj->notify_ = notify_;
newObj->seconds_ = seconds_;
newObj->dirty_ = dirty_;
return newObj;
}
- (void)dealloc {
#ifdef DEBUG
NSLog(@"+++++++++++++++++++++++++++++++++++++");
NSLog(@"Dealloc: %@", name_);
[self debugURL];
#endif
[name_ release];
[kind_ release];
[url_ release];
[super dealloc];
}
// Because I am using the image in two different places, different size
// I create them at the time of need.
- (NSImage *)image {
NSImage *img = nil;
if (isFile_) {
// check if the file exists and ask the workspace for the icon
NSFileManager *fm = [[NSFileManager alloc] init];
if ([fm fileExistsAtPath:[url_ path]]) {
// get the icon for the file
img = [[NSWorkspace sharedWorkspace] iconForFile:[url_ path]];
} else {
// Display a question mark for missing files
// That doesn't mean the file won't be unavailable at the time
// it's needed by the daemon application
img = [self createIconImage:kQuestionMarkIcon];
}
[fm release];
} else {
NSString *scheme = [url_ scheme];
// assign an icon base on the scheme
if ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame)
img = [self createIconImage:kInternetLocationHTTPIcon];
else if ([scheme caseInsensitiveCompare:@"ftp"] == NSOrderedSame)
img = [self createIconImage:kInternetLocationFTPIcon];
else if ([scheme caseInsensitiveCompare:@"mailto"] == NSOrderedSame)
img = [self createIconImage:kInternetLocationMailIcon];
else if ([scheme caseInsensitiveCompare:@"news"] == NSOrderedSame)
img = [self createIconImage:kInternetLocationNewsIcon];
else
img = [self createIconImage:kInternetLocationGenericIcon];
}
return img;
}
- (NSString *)toolTip {
NSString *tip = nil;
if (isFile_) {
// get file system path from NSURL
CFStringRef filePath = CFURLCopyFileSystemPath((CFURLRef)url_, kCFURLPOSIXPathStyle);
if (filePath != nil) {
// create a new autorelease NSString
tip =[NSString stringWithString:(NSString *)filePath];
CFRelease(filePath);
}
} else
tip = [url_ absoluteString];
return tip;
}
#pragma mark -
#pragma mark User control properties
- (void)setHide:(BOOL)aHide {
if (hide_ != aHide) {
hide_ = aHide;
[self setDirty:YES];
}
}
- (void)setLaunchSeconds:(NSUInteger)seconds {
if (seconds_ != seconds) {
seconds_ = seconds;
[self setDirty:YES];
}
}
- (void)setNotifyLaunch:(BOOL)notify {
if (notify_ != notify) {
notify_ = notify;
[self setDirty:YES];
}
}
#pragma mark -
#pragma mark NSCoding Protocol
// Friday Q&A 2010-08-12: Implementing NSCoding
// http://www.mikeash.com/pyblog/friday-qa-2010-08-12-implementing-nscoding.html
// http://stackoverflow.com/questions/2944823/iphone-is-initwithcoder-an-exception-to-the-usual-designated-initializer-desig
// TODO: Refactor my initWithCoder methods
- (id)initWithCoder:(NSCoder *)coder {
// first thing we do is decode the path information
NSString *path = (NSString *)[coder decodeObjectForKey:@"Path"];
if ((self = [self initWithPath:path])) {
// TODO: decode the additional properties
//self->name_ = @"Help";
//[self->name_ retain];
hide_ = [coder decodeBoolForKey:@"Hide"];
notify_ = [coder decodeBoolForKey:@"Notify"];
seconds_ = [coder decodeIntegerForKey:@"Seconds"];
// because I just init from a coder
// we are not dirty
dirty_ = NO;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
#ifdef DEBUG
NSLog(@"===================================");
NSLog(@"Encode: %@", name_);
[self debugURL];
#endif
// If the url_ has a file reference, archive that
NSString *path = [[url_ fileReferenceURL] absoluteString];
if (path == nil) // if no file reference, then use the URL absolute path
path = [url_ absoluteString];
[coder encodeObject:path forKey:@"Path"];
[coder encodeBool:hide_ forKey:@"Hide"];
[coder encodeBool:notify_ forKey:@"Notify"];
[coder encodeInteger:seconds_ forKey:@"Seconds"];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment