/* Copyright (C) 2002-2003, Jeffrey D. Argast. The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. Permission is hereby granted to use, copy, modify, and distribute this software or portions thereof for any purpose, without fee, subject to these conditions: (1) If any part of the source code is distributed, then this statement must be included, with this copyright and no-warranty notice unaltered. (2) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. */ #import "AppController.h" #import "DepotController.h" #import "AppUtils.h" #import "PreferenceController.h" #import "AppDefaults.h" #import "PerforceAction.h" #import "PerforceActionClient.h" #import "PerforceActionChange.h" #import "PerforceActionBranch.h" #import "PerforceActionLabel.h" #import "PerforceActionJob.h" #import "PerforceActionUser.h" #import "PerforceActionAdd.h" #import "PerforceActionChange.h" #import "PerforceActionSubmit.h" #import "EditSheetController.h" #import "MessageDefs.h" #import "TextFieldDialogController.h" #import "EditConfigurationsController.h" #import "PerforceConfigurationsList.h" #import "PerforceConfiguration.h" #import "DepotExpander.h" #import "EditBookmarksController.h" static NSString* kSpaceStr = @" "; BOOL ConvertStringToRect (NSString* rectString, NSRect* outRect); BOOL ConvertStringToRect (NSString* rectString, NSRect* outRect) { if ( !rectString ) return NO; NSScanner* rectScanner = [NSScanner scannerWithString:rectString]; if ( [rectScanner scanFloat:&(outRect->origin.x)] == NO ) return NO; if ( [rectScanner scanFloat:&(outRect->origin.y)] == NO ) return NO; if ( [rectScanner scanFloat:&(outRect->size.width)] == NO ) return NO; if ( [rectScanner scanFloat:&(outRect->size.height)] == NO ) return NO; return YES; } NSString* ConvertRectToString (NSRect rect); NSString* ConvertRectToString (NSRect rect) { NSMutableString* retValue = [[[NSMutableString alloc] init] autorelease]; NSNumber* x = [NSNumber numberWithFloat:rect.origin.x]; NSNumber* y = [NSNumber numberWithFloat:rect.origin.y]; NSNumber* width = [NSNumber numberWithFloat:rect.size.width]; NSNumber* height = [NSNumber numberWithFloat:rect.size.height]; [retValue appendString:[x stringValue]]; [retValue appendString:kSpaceStr]; [retValue appendString:[y stringValue]]; [retValue appendString:kSpaceStr]; [retValue appendString:[width stringValue]]; [retValue appendString:kSpaceStr]; [retValue appendString:[height stringValue]]; return retValue; } @interface AppController (PrivateMethods) - (TextFieldDialogController*) getDialog; - (NSString*) getUserInput:(NSString*)title; - (void) submitChangeOK: (NSString*) contentString; - (void) resultFromPerforceSubmit: (PerforceActionSubmit*) action; - (void) resultFromPerforceChangeNew: (PerforceActionChangeNew*) action; - (void) resultFromPerforceClientIn: (PerforceActionClientIn*) action; - (void) resultFromPerforceClientOut: (PerforceActionClientGet*) action; - (void) resultFromPerforceBranchIn: (PerforceActionBranchIn*) action; - (void) resultFromPerforceBranchOut: (PerforceActionBranchGet*) action; - (void) resultFromPerforceLabelIn: (PerforceActionLabelIn*) action; - (void) resultFromPerforceLabelOut: (PerforceActionLabelGet*) action; - (void) resultFromPerforceUserIn: (PerforceActionUserIn*) action; - (void) resultFromPerforceUserOut: (PerforceActionUserGet*) action; - (void) resultFromPerforceJobIn: (PerforceActionJobIn*) action; - (void) resultFromPerforceJobOut: (PerforceActionJobGet*) action; - (void) resultFromPerforceChangeOut: (PerforceActionChangeNew*) action; - (void) resultFromPerforceChangeIn: (PerforceActionChangeIn*) action; - (void) editClientOK: (NSString*) contentString; - (void) editChangeOK: (NSString*) contentString; - (void) editBranchOK: (NSString*) contentString; - (void) editLabelOK: (NSString*) contentString; - (void) editUserOK: (NSString*) contentString; - (void) editJobOK: (NSString*) contentString; - (void) updateDepotViewMenus; - (void) updateDeletedFilesMenu; - (void) handleShowEntireDepotChanged: (NSNotification*) notification; - (void) handleShowDeletedFilesChanged: (NSNotification*) notification; - (void) handleClientChanged: (NSNotification*) notification; - (void) setClientRoot; - (void) updateConfigurationMenu; - (void) updateBookmarksMenu; - (NSString*) readStringFromPasteboard:(NSPasteboard*)pb; @end @implementation AppController - (void) awakeFromNib { AppDefaults* appDefaults = [AppDefaults defaultAppDefaults]; [appDefaults setEnvVars]; NSView* horzSplitViewChild0 = [[fHorzSplitView subviews] objectAtIndex:0]; NSView* horzSplitViewChild1 = [[fHorzSplitView subviews] objectAtIndex:1]; NSView* vertSplitViewChild0 = [[fVertSplitView subviews] objectAtIndex:0]; NSView* vertSplitViewChild1 = [[fVertSplitView subviews] objectAtIndex:1]; NSString* horzSplitViewChildFrame0 = [[NSUserDefaults standardUserDefaults] objectForKey:@"HorizontalSplitterFrame0"]; NSString* horzSplitViewChildFrame1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"HorizontalSplitterFrame1"]; NSString* vertSplitViewChildFrame0 = [[NSUserDefaults standardUserDefaults] objectForKey:@"VerticalSplitterFrame0"]; NSString* vertSplitViewChildFrame1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"VerticalSplitterFrame1"]; NSRect frame0, frame1; if ( ConvertStringToRect (horzSplitViewChildFrame0, &frame0) && ConvertStringToRect (horzSplitViewChildFrame1, &frame1) ) { [horzSplitViewChild0 setFrame:frame0]; [horzSplitViewChild1 setFrame:frame1]; [fHorzSplitView adjustSubviews]; } if ( ConvertStringToRect (vertSplitViewChildFrame0, &frame0) && ConvertStringToRect (vertSplitViewChildFrame1, &frame1) ) { [vertSplitViewChild0 setFrame:frame0]; [vertSplitViewChild1 setFrame:frame1]; [fVertSplitView adjustSubviews]; } NSData* configData = [[NSUserDefaults standardUserDefaults] dataForKey:@"DepotBookmarks"]; if ( configData ) { fBookmarks = [[NSUnarchiver unarchiveObjectWithData:configData] mutableCopy]; } NSNotificationCenter* nCenter = [NSNotificationCenter defaultCenter]; [nCenter addObserver:self selector:@selector(handleShowEntireDepotChanged:) name:kDefaultsShowEntireDepotChanged object:nil]; [nCenter addObserver:self selector:@selector(handleShowDeletedFilesChanged:) name:kDefaultsShowDeletedFilesChanged object:nil]; [nCenter addObserver:self selector:@selector(handleClientChanged:) name:kDefaultsClientChanged object:nil]; [nCenter addObserver:self selector:@selector(handleConfigurationsChanged:) name:kDefaultsConfigurationsChanged object:nil]; [self setClientRoot]; [self updateDepotViewMenus]; [self updateDeletedFilesMenu]; [self updateConfigurationMenu]; [self updateBookmarksMenu]; } - (void) dealloc { [fPrefController release]; [fEditSheetController release]; [TextFieldDialogController release]; [fEditConfigurationsController release]; [fClientRoot release]; NSNotificationCenter* nCenter = [NSNotificationCenter defaultCenter]; [nCenter removeObserver:self]; [super dealloc]; } - (IBAction) showPreferencePanel: (id) sender { if ( !fPrefController ) { fPrefController = [[PreferenceController alloc] init]; } else { [fPrefController aboutToShowWindow]; } [fPrefController showWindow:self]; } - (IBAction) editConfigurations: (id) sender { if ( !fEditConfigurationsController ) { fEditConfigurationsController = [[EditConfigurationsController alloc] init]; } else { [fEditConfigurationsController aboutToShowWindow]; } [fEditConfigurationsController showWindow:self]; } - (void) applicationDidFinishLaunching: (NSNotification *) aNotification { CreateAppTempDir(); [fDepotController appFinishedLaunching]; [fTabViewDelegate appFinishedLaunching]; } - (void)applicationWillTerminate:(NSNotification *)aNotification { [PerforceAction abortAllActions]; NSView* horzSplitViewChild0 = [[fHorzSplitView subviews] objectAtIndex:0]; NSView* horzSplitViewChild1 = [[fHorzSplitView subviews] objectAtIndex:1]; NSView* vertSplitViewChild0 = [[fVertSplitView subviews] objectAtIndex:0]; NSView* vertSplitViewChild1 = [[fVertSplitView subviews] objectAtIndex:1]; NSString* horzSplitViewChildFrame0 = ConvertRectToString ([horzSplitViewChild0 frame]); NSString* horzSplitViewChildFrame1 = ConvertRectToString ([horzSplitViewChild1 frame]); NSString* vertSplitViewChildFrame0 = ConvertRectToString ([vertSplitViewChild0 frame]); NSString* vertSplitViewChildFrame1 = ConvertRectToString ([vertSplitViewChild1 frame]); [[NSUserDefaults standardUserDefaults] setObject:horzSplitViewChildFrame0 forKey:@"HorizontalSplitterFrame0"]; [[NSUserDefaults standardUserDefaults] setObject:horzSplitViewChildFrame1 forKey:@"HorizontalSplitterFrame1"]; [[NSUserDefaults standardUserDefaults] setObject:vertSplitViewChildFrame0 forKey:@"VerticalSplitterFrame0"]; [[NSUserDefaults standardUserDefaults] setObject:vertSplitViewChildFrame1 forKey:@"VerticalSplitterFrame1"]; RemoveAppTempDir(); } - (IBAction) editClient: (id) sender { [PerforceActionClientGet defaultRunFor:self selector:@selector(resultFromPerforceClientOut:) identifier:nil]; } - (IBAction) submitDefaultChangelist: (id) sender { [PerforceActionChangeNew defaultRunFor:self selector:@selector(resultFromPerforceChangeNew:)]; } - (void)windowWillClose:(NSNotification *)aNotification { [NSApp terminate:self]; } // Switch to client view of depot - (IBAction) clientViewOfDepot: (id) sender { [fDepotController clientViewOfDepot:sender]; } // switch to entire view of depot - (IBAction) entireViewOfDepot: (id) sender { [fDepotController entireViewOfDepot:sender]; } // Show deleted files - (IBAction) showDeletedFiles: (id) sender { [fDepotController showDeletedFiles:sender]; } // Hide deleted files - (IBAction) hideDeletedFiles: (id) sender { [fDepotController hideDeletedFiles:sender]; } - (IBAction) setActiveConfiguration: (NSMenuItem*) sender { [[AppDefaults defaultAppDefaults] setActiveConfiguration:[sender title]]; } - (IBAction) executeBookmark: (NSMenuItem*) sender { [DepotExpander expandPath:[sender title] depot:fDepotController usep4Where:NO]; } - (IBAction) paste:(id)sender { NSPasteboard* pb = [NSPasteboard generalPasteboard]; NSString* depotPath = [self readStringFromPasteboard:pb]; [DepotExpander expandPath:depotPath depot:fDepotController usep4Where:YES]; } - (IBAction) addFiles: (id) sender { NSOpenPanel* panel = [NSOpenPanel openPanel]; [panel setAllowsMultipleSelection:YES]; [panel beginSheetForDirectory:fClientRoot file:nil types:nil modalForWindow:[NSApp mainWindow] modalDelegate:self didEndSelector:@selector(addFilesDidEnd:returnCode:contextInfo:) contextInfo:nil]; } - (void) addFilesDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { NSArray* files = [sheet filenames]; if ( [files count] > 0 ) { [PerforceActionAdd defaultAddFiles:files]; } } - (IBAction) newChangelist:(id)sender { [PerforceActionChangeNew defaultRunFor:self selector:@selector(resultFromPerforceChangeOut:)]; } - (IBAction) newBranch:(id)sender { NSString* name = [self getUserInput:@"Enter New Branch Name"]; if ( name ) { [PerforceActionBranchGet defaultRunFor:self selector:@selector(resultFromPerforceBranchOut:) identifier:name]; } } - (IBAction) newLabel:(id)sender { NSString* name = [self getUserInput:@"Enter New Label Name"]; if ( name ) { [PerforceActionLabelGet defaultRunFor:self selector:@selector(resultFromPerforceLabelOut:) identifier:name]; } } - (IBAction) newUser:(id)sender { NSString* name = [self getUserInput:@"Enter New User Name"]; if ( name ) { [PerforceActionUserGet defaultRunFor:self selector:@selector(resultFromPerforceUserOut:) identifier:name]; } } - (IBAction) newClient:(id)sender { NSString* name = [self getUserInput:@"Enter New Client Name"]; if ( name ) { [PerforceActionClientGet defaultRunFor:self selector:@selector(resultFromPerforceClientOut:) identifier:name]; } } - (IBAction) newJob:(id)sender { [PerforceActionJobNew defaultRunFor:self selector:@selector(resultFromPerforceJobOut:)]; } - (IBAction) refreshAllViews:(id)sender { SendNotification (kRefreshAllViews); } - (IBAction) editBookmarks: (id) sender { [fBookmarksController setBookmarks:fBookmarks]; [NSApp beginSheet:fEditBookmarksPanel modalForWindow:[NSApp mainWindow] modalDelegate:self didEndSelector:@selector(editBookmarksDidEnd:returnCode:contextInfo:) contextInfo:nil]; } - (void) editBookmarksDidEnd:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo { [fEditBookmarksPanel orderOut:self]; if ( returnCode == 1 ) { [fBookmarks release]; fBookmarks = [[fBookmarksController bookmarks] mutableCopy]; NSData* listData = [NSArchiver archivedDataWithRootObject:fBookmarks]; [[NSUserDefaults standardUserDefaults] setObject:listData forKey:@"DepotBookmarks"]; [self updateBookmarksMenu]; } } - (void) addDepotBookmark:(NSString*)bookmark { [fBookmarks addObject:bookmark]; NSData* listData = [NSArchiver archivedDataWithRootObject:fBookmarks]; [[NSUserDefaults standardUserDefaults] setObject:listData forKey:@"DepotBookmarks"]; [self updateBookmarksMenu]; } - (void) showEditSheet:(id)sender contentData:(NSString*)contentData endSelector:(SEL)endSelector title:(NSString*)titleString; { if ( !fEditSheetController ) { fEditSheetController = [[EditSheetController alloc] init]; } [fEditSheetController showSheet:sender selector:endSelector withContent:contentData title:titleString]; } - (BOOL) validateMenuItem:(NSMenuItem*)menuItem { if ( [NSApp modalWindow] != nil ) { return NO; } SEL selector = [menuItem action]; if ( selector == @selector(editClient:) ) { NSString* clientName = [[AppDefaults defaultAppDefaults] getPerforceClient]; NSMutableString* menuName = [NSMutableString stringWithString:@"Edit "]; [menuName appendString:clientName]; [menuName appendString:@"..."]; [menuItem setTitle:menuName]; } return YES; } @end // // // // @implementation AppController (PrivateMethods) - (TextFieldDialogController*) getDialog { if ( !fTextFieldDialogController ) { fTextFieldDialogController = [[TextFieldDialogController alloc] init]; } return fTextFieldDialogController; } - (NSString*) getUserInput:(NSString*)title { TextFieldDialogController* dialog = [self getDialog]; [dialog showDialog:title]; NSString* retVal = [dialog getData]; if ( retVal && ([retVal length] > 0) ) { return retVal; } return nil; } - (void) submitChangeOK: (NSString*) contentString { [PerforceActionSubmit defaultRunFor:self selector:@selector(resultFromPerforceSubmit:) form:contentString]; } - (void) resultFromPerforceSubmit: (PerforceActionSubmit*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(submitChangeOK:) title:@"Edit Changelist"]; } } - (void) resultFromPerforceChangeNew: (PerforceActionChangeNew*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(submitChangeOK:) title:@"Edit Changelist"]; } } - (void) resultFromPerforceClientIn: (PerforceActionClientIn*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(editClientOK:) title:@"Edit Changelist"]; } } - (void) resultFromPerforceClientOut: (PerforceActionClientGet*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(editClientOK:) title:@"Edit Changelist"]; } } - (void) resultFromPerforceBranchIn: (PerforceActionBranchIn*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(editBranchOK:) title:@"Edit Branch Specification"]; } } - (void) resultFromPerforceBranchOut: (PerforceActionBranchGet*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(editBranchOK:) title:@"Edit Branch Specification"]; } } - (void) resultFromPerforceLabelIn: (PerforceActionLabelIn*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(editLabelOK:) title:@"Edit Label Specification"]; } } - (void) resultFromPerforceLabelOut: (PerforceActionLabelGet*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(editLabelOK:) title:@"Edit Label Specification"]; } } - (void) resultFromPerforceUserIn: (PerforceActionUserIn*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(editUserOK:) title:@"Edit User Specification"]; } } - (void) resultFromPerforceUserOut: (PerforceActionUserGet*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(editUserOK:) title:@"Edit User Specification"]; } } - (void) resultFromPerforceJobIn: (PerforceActionJobIn*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(editJobOK:) title:@"Edit Job Specification"]; } } - (void) resultFromPerforceJobOut: (PerforceActionJobGet*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(editJobOK:) title:@"Edit Job Specification"]; } } - (void) resultFromPerforceChangeIn: (PerforceActionChangeIn*) action { if ( [action wasError] ) { [self showEditSheet:self contentData:[action getForm] endSelector:@selector(editChangeOK:) title:@"Edit Changelist"]; } } - (void) resultFromPerforceChangeOut: (PerforceActionChangeNew*) action { if ( [action wasSuccess] ) { [self showEditSheet:self contentData:[action getOutput] endSelector:@selector(editChangeOK:) title:@"Edit Changelist"]; } } - (void) editClientOK: (NSString*) contentString { [PerforceActionClientIn defaultRunFor:self selector:@selector(resultFromPerforceClientIn:) form:contentString]; } - (void) editChangeOK: (NSString*) contentString { [PerforceActionChangeIn defaultRunFor:self selector:@selector(resultFromPerforceChangeIn:) form:contentString]; } - (void) editBranchOK: (NSString*) contentString; { [PerforceActionBranchIn defaultRunFor:self selector:@selector(resultFromPerforceBranchIn:) form:contentString]; } - (void) editLabelOK: (NSString*) contentString; { [PerforceActionLabelIn defaultRunFor:self selector:@selector(resultFromPerforceLabelIn:) form:contentString]; } - (void) editUserOK: (NSString*) contentString; { [PerforceActionUserIn defaultRunFor:self selector:@selector(resultFromPerforceUserIn:) form:contentString]; } - (void) editJobOK: (NSString*) contentString; { [PerforceActionJobIn defaultRunFor:self selector:@selector(resultFromPerforceJobIn:) form:contentString]; } - (void) handleShowEntireDepotChanged: (NSNotification*) notification { [self updateDepotViewMenus]; } - (void) handleShowDeletedFilesChanged: (NSNotification*) notification { [self updateDeletedFilesMenu]; } - (void) handleClientChanged: (NSNotification*) notification { [self setClientRoot]; } - (void) handleConfigurationsChanged: (NSNotification*) notification { [self updateConfigurationMenu]; } - (void) updateDepotViewMenus { BOOL entireDepotShown = [[AppDefaults defaultAppDefaults] getShowEntireDepot]; if ( entireDepotShown ) { [fShowEntireViewMenu setState:NSOnState]; [fShowClientViewMenu setState:NSOffState]; } else { [fShowEntireViewMenu setState:NSOffState]; [fShowClientViewMenu setState:NSOnState]; } } - (void) updateDeletedFilesMenu { BOOL deletedFilesShown = [[AppDefaults defaultAppDefaults] getShowDeletedFiles]; if ( deletedFilesShown ) { [fShowHideDeletedFilesMenu setTitle:@"Hide Deleted Files"]; [fShowHideDeletedFilesMenu setAction:@selector(hideDeletedFiles:)]; } else { [fShowHideDeletedFilesMenu setTitle:@"Show Deleted Files"]; [fShowHideDeletedFilesMenu setAction:@selector(showDeletedFiles:)]; } } static NSString* kEndOfLineToken = @"\n"; static NSString* kRootToken = @"Root:"; static NSString* kSlashToken = @"/"; - (void) resultForGetClientRoot: (PerforceActionClientGet*) action { if ( [action wasSuccess] ) { NSString* clientInfo = [action getOutput]; NSString* resultString; NSScanner* clientScanner = [NSScanner scannerWithString:clientInfo]; while ( [clientScanner scanUpToString:kEndOfLineToken intoString:&resultString] == YES ) { if ( [resultString characterAtIndex:0] != '#' ) { NSScanner* subScanner = [NSScanner scannerWithString:resultString]; if ( [subScanner scanString:kRootToken intoString:nil] == YES ) { [subScanner scanUpToString:kSlashToken intoString:nil]; unsigned int scanLoc = [subScanner scanLocation] + 1; if ( scanLoc < [resultString length] ) { fClientRoot = [[resultString substringFromIndex:scanLoc] retain]; } else { fClientRoot = nil; } break; } } } } } - (void) setClientRoot { [PerforceActionClientGet defaultRunFor:self selector:@selector(resultForGetClientRoot:) identifier:nil]; } - (void) updateConfigurationMenu { int numItems = [fConfigurationMenu numberOfItems]; int n; // remove everything but the separator and edit configurations item for ( n = (numItems - 3); n >= 0; n-- ) { [fConfigurationMenu removeItemAtIndex:n]; } PerforceConfigurationsList* configs = [[AppDefaults defaultAppDefaults] getConfigurations]; int activeConfig = [configs indexOfActiveConfiguration]; numItems = [configs count]; for ( n = 0; n < numItems; n++ ) { PerforceConfiguration* config = [configs configurationAtIndex:n]; NSMenuItem* newItem = [fConfigurationMenu insertItemWithTitle:[config configurationName] action:@selector(setActiveConfiguration:) keyEquivalent:@"" atIndex:n]; [newItem setTarget:self]; if ( activeConfig == n ) { [newItem setState:NSOnState]; } } } - (void) updateBookmarksMenu { int numItems = [fBookmarksMenu numberOfItems]; int n; // remove everything but the separator and edit configurations item for ( n = (numItems - 4); n >= 0; n-- ) { [fBookmarksMenu removeItemAtIndex:n]; } if ( fBookmarks ) { numItems = [fBookmarks count]; for ( n = 0; n < numItems; n++ ) { NSMenuItem* newItem = [fBookmarksMenu insertItemWithTitle:[fBookmarks objectAtIndex:n] action:@selector(executeBookmark:) keyEquivalent:@"" atIndex:n]; [newItem setTarget:self]; } } } - (NSString*) readStringFromPasteboard:(NSPasteboard*)pb { NSString* value = nil; NSString* type = [pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]; if ( type ) { value = [pb stringForType:NSStringPboardType]; } return value; } @end