NXRunAlertPanel ( "Startup", "Unable to open startup folder: %s",
"Ok", NULL, NULL, path );
}
}
isAutoLaunch = NO; // Turn this off after initial setup
isSetup = YES;
return ( self );
}
- (BOOL)cleanup
/*
Cleanup the FolderController before ending operations. Returns YES if it is ok to terminate, NO otherwise ( e.g. there are unsaved folders ). This is intended to be called from -appWillTerminate:
Called when Locus is activated (becomes the active app). Set the App Icon to show an active state.
*/
{
if ( ![NXApp isActive] ) [NXApp activateSelf:NO];
[appIconView setIcon:"ActiveIcon"];
if ( ![[[NXApp keyWindow] delegate] isKindOf:[Folder class]] )
[[keyFolder viewer] makeKeyWindow];
return ( self );
}
- inactive:sender
/*
Called after Locus is deactived -- is not longer the active app. Set the App Icon to show an inactive state.
*/
{
[appIconView setIcon:"InactiveIcon"];
return ( self );
}
- doAutoLaunch:sender
/*
Launch all items in all groups in keyFolder that are flagged as AutoLaunch. This is performed on all startup Folders as they are opened when Locus is auto-launched. This can also be done using the AutoLaunch menu item.
Changes a full pathname to a Folder into a relative path, as it is shown in the Preferences browser, and as it is stored in Defaults database. Folders in ~/Library/Locus (LIBRARY_DIR) are shown only as the folder name itself without a path. Folders located elsewhere in the user's home directory are shown as ~/..../Folder.locus. All other folders are shown with their full path name.
p = path + strlen ( homeDir ) + 1; // +1 to get past the '/'
if ( strstr ( p, LIBRARY_DIR ) == p ) {
// The folder is in the LIBRARY_DIR
p += strlen ( LIBRARY_DIR ) + 1; // +1 to get past last '/'
strcpy ( relativePath, p );
} else {
// The folder is somewhere other than in LIBRARY_DIR
sprintf ( relativePath, "~/%s", p );
}
} else {
// Folder is not anywhere in user's home dir
strcpy ( relativePath, path );
}
return ( relativePath );
}
- readFolderFromPath:(const char *)path
/*
Read a Folder (and its Groups) located by path (which should be the full pathname). Returns a new Folder object. If this is called during setup -- i.e. when the startup folders are beoing opened -- then creates an empty folder object even if it can't read it.
Save the Folder object by writing both the Folder info and the Groups. The Folder is saved to the path specified by [aFolder filename]
*/
{
[aFolder writeInfo];
[aFolder writeGroups];
return ( self );
}
- openFolder:(const char *)path
/*
Open the folder specified by path and add it to folderList
*/
{
id newFolder;
if ( !(newFolder = [self readFolderFromPath:path]) )
return ( nil ); // Unable to read the Folder at path
if ( ![self addFolder:newFolder] ) {
// Unable to add the Folder to our folderList
[newFolder free];
return ( nil );
}
[newFolder showSelf:self];
[self makeKeyFolder:newFolder];
if ( isAutoLaunch ) [self doAutoLaunch:self];
// Perform autoLaunch only at launch-time
return ( self );
}
- openFolderFromOpenPanel:sender
/*
Choose Folders to be opened using an OpenPanel. Each time this method is called, the directory is initially the the last directory selected (the first time it is set to the home dir).
if ( [openPanel runModalForDirectory:directory file:NULL types:types] ) {
strcpy ( directory, [openPanel directory] ); // Save directory
files = [openPanel filenames];
i = 0;
while ( files[i] ) {
sprintf ( path, "%s/%s", directory, files[i] );
[self openFolder:path];
i++;
}
}
return ( self );
}
- newFolder:sender
/*
Create a new, un-titled Folder, add it to the Folder list
*/
{
id newFolder = [[Folder new] obtainViewer:nil];
if ( ![self addFolder:newFolder] ) [newFolder free];
else [self makeKeyFolder:newFolder];
return ( newFolder );
}
- saveKeyFolder:sender
{
[self saveFolder:keyFolder];
return ( self );
}
- saveKeyFolderAs:sender
{
[self saveFolderAs:keyFolder];
return ( self );
}
- saveAllFolders:sender
/*
Go through the folderList and save all folders that have been changed.
*/
{
int i, count;
count = [folderList count];
for ( i=0; i<count; i++ )
if ( [[folderList objectAt:i] isChanged] )
[self saveFolder:[folderList objectAt:i]];
return ( self );
}
- revertKeyFolder:sender
/*
Undo all changes to the keyFolder but replacing it with the last saved version. This method reads the saved folder and replaces the changed one with it.
*/
{
id revertedFolder;
if ( ![keyFolder filename] ) {
// Don't do anything if the Folder has never been saved
NXBeep();
return ( self );
}
if ( !(revertedFolder = [self readFolderFromPath:[keyFolder filename]]) ) {
NXRunAlertPanel ( "Revert", "Unable to restore the Folder.",
If keyWindow is the keyFolder's viewer, all selected items are copied to the itemPboard and removed. Otherwise, this message is forwarded to the first responder.
*/
{
id keyWindow = [NXApp keyWindow];
// The keyWindow is the keyFolder's viewer
if ( keyWindow == [keyFolder viewer] ) {
[self copy:self]; // Copy the items to the pasteboard
If keyWindow is the keyFolder's viewer, all items on the itemPboard are added to the currentGroup. Otherwise this message is forwarded to firstResponder
*/
{
id keyWindow = [NXApp keyWindow];
const char * const *types;
char *list = NULL;
int len, i=0;
char *s, *tab, path[MAXPATHLEN+1];
if ( keyWindow == [keyFolder viewer] ) {
if ( ![keyFolder currentGroup] ) {
NXBeep();
return ( nil );
}
// Get list of items from itemPboard
types = [itemPboard types];
while ( types[i] ) {
if ( !strcmp ( types[i], NXFilenamePboardType ) ) {
if ( ![itemPboard readType:NXFilenamePboardType
data:&list length:&len] ) {
list = NULL;
len = 0;
}
break;
}
i++;
}
// Add all the items in the list
if ( list ) {
s = list;
do {
// Read the next path, at s
sscanf ( s, "%[^\t]", path );
// Add the path
[[keyFolder currentGroup] addItem:path];
// Move s to next path
tab = index ( s, '\t' ); // Find next tab
if ( tab ) s = tab + 1;
else s = NULL;
} while ( s );
// Free the memory used by list
vm_deallocate ( task_self(), (vm_address_t)list, len );
These messages are forwarded from the actual View that they occured in. (The view should have called [folderController setDragDest:self] in this method before fowarding it here. The View will be either the AppIconView, one of the ActivatorBars, or a GroupBrowser.
This method performs the actual operation for a dragging session. In this case, this means it adds the files/paths that were dragged in as items in the keyFolder's current group, or the folder they were dragged into if not the key folder.
*/
{
Folder *destFolder = nil;
char *paths;
int pLen;
char *p, path[MAXPATHLEN+1];
// Determine the folder being dragged into
if ( dragDest == appIconView || dragDest == activator )
destFolder = keyFolder;
else if ( [dragDest isKindOf:[GroupBrowser class]] )
destFolder = [[dragDest window] delegate];
if ( ![destFolder currentGroup] ) {
NXRunAlertPanel ( "Error",
"No destination folder and/or group to drag into!",
Update the menu items to reflect current status. Mostly this means enabling or disabling them depending on if their action is available. This method is called from updateDisplay, instead of being the Menu's update action, which if hopefully more efficient.
*/
{
if ( !keyFolder ) {
[menu_SaveFolder setEnabled:NO];
[menu_SaveFolderAs setEnabled:NO];
[menu_SaveAll setEnabled:NO];
[menu_RevertFolder setEnabled:NO];
[menu_NewGroup setEnabled:NO];
[menu_DeleteGroup setEnabled:NO];
[menu_LaunchGroup setEnabled:NO];
[menu_SortGroup setEnabled:NO];
[menu_CleanGroup setEnabled:NO];
[menu_DynamicUpdate setEnabled:NO];
[menu_AddItem setEnabled:NO];
[menu_LaunchItem setEnabled:NO];
[menu_DeleteItem setEnabled:NO];
} else {
[menu_SaveFolder setEnabled:YES];
[menu_SaveFolderAs setEnabled:YES];
[menu_SaveAll setEnabled:YES];
[menu_RevertFolder setEnabled:YES];
[menu_NewGroup setEnabled:YES];
if ( [keyFolder currentGroup] ) {
[menu_DeleteGroup setEnabled:YES];
[menu_LaunchGroup setEnabled:YES];
[menu_SortGroup setEnabled:YES];
[menu_CleanGroup setEnabled:YES];
[menu_DynamicUpdate setEnabled:YES];
[menu_AddItem setEnabled:YES];
[menu_LaunchItem setEnabled:YES];
[menu_DeleteItem setEnabled:YES];
} else {
[menu_DeleteGroup setEnabled:NO];
[menu_LaunchGroup setEnabled:NO];
[menu_SortGroup setEnabled:NO];
[menu_CleanGroup setEnabled:NO];
[menu_DynamicUpdate setEnabled:NO];
[menu_AddItem setEnabled:NO];
[menu_LaunchItem setEnabled:NO];
[menu_DeleteItem setEnabled:NO];
}
}
[menu_HideOnDeactivate setTitle:
(hideDeactive ? "Don't hide" : "Hide on deactivate")];
return ( self );
}
- updateDisplay
/*
Update the display of the keyFolder, and the inspector.
*/
{
[keyFolder showSelf:self];
[inspector update];
return ( self );
}
- updateDisplay:sender
/*
Just calls -updateDisplay. This is basically used so updateDisplay can be used with a delayed perform ( perform:with:afterDelay:cancelPrevious: )